Merge pull request #1 from pcottle/master

Upstream update
This commit is contained in:
Daniel Le Berre 2021-01-23 13:48:37 +01:00 committed by GitHub
commit e8c94d90b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
127 changed files with 20821 additions and 6357 deletions

15
.gitignore vendored
View file

@ -1,12 +1,10 @@
# NPM
# NPM and Yarn
npm-debug.log
yarn-error.log
node_modules/
# Build artifacts and asset stuff
build/*
build/bundle.js
build/bundle.*.js
build/main.*.css
screens
FontAwesome-Vectors.pdf
index.html
@ -14,6 +12,9 @@ index.html
# Vim swaps
*.sw*
# sed backups
*.bak
# Annoying mac stuff
.DS_STORE
@ -22,7 +23,6 @@ index.html
*.xcworkspace
xcuserdata
UserInterfaceState.xcuserstate
xcuserdata/
*.pbxuser
*.perspective
@ -40,7 +40,6 @@ xcuserdata/
.User.xcconfig
xcuserdata
Tools/xctool/build
Tools/clang/analyzer/build
Tools/clang/libtooling/build
@ -50,7 +49,3 @@ VendorLib/Breakpad/src/tools/mac/dump_syms/build
DerivedData
VendorLib/clang/lib/arc
VendorLib/clang/lib/c++
*.swp

9
.gitpod.yml Normal file
View file

@ -0,0 +1,9 @@
ports:
- port: 8000
onOpen: open-preview
tasks:
- init: yarn install
command: >
yarn gulp fastBuild &&
printf "\nWelcome to Learn Git Branching\nTo rebuild the app, simply run 'yarn gulp fastBuild' and reload index.html.\n\n" &&
python3 -m http.server 8000 2>/dev/null

41
.jshintrc Normal file
View file

@ -0,0 +1,41 @@
{
"esversion": 6,
"curly": true,
"eqeqeq": false,
"regexp": false,
"nonew": false,
"latedef": false,
"forin": false,
"globalstrict": false,
"node": true,
"immed": true,
"newcap": true,
"noarg": true,
"bitwise": true,
"sub": true,
"undef": true,
"unused": true,
"trailing": true,
"devel": true,
"jquery": true,
"nonstandard": true,
"boss": true,
"eqnull": true,
"browser": true,
"debug": true,
"globals": {
"casper": true,
"Raphael": true,
"require": true,
"console": true,
"describe": true,
"expect": true,
"it": true,
"runs": true,
"waitsFor": true,
"exports": true,
"module": true,
"prompt": true,
"process": true
}
}

View file

@ -1,4 +1,16 @@
sudo: false
language: node_js
node_js:
- "4.1"
- "5.3"
- "10"
- "8"
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH="$HOME/.yarn/bin:$PATH"
cache:
yarn: true
directories:
- "node_modules"
script:
- ./checkgit.sh "Source files were modified before build; is yarn.lock out of sync with package.json?" || travis_terminate $?
- yarn gulp
- ./checkgit.sh "Source files were modified by the build" || travis_terminate $?

View file

@ -1,256 +0,0 @@
var _ = require('underscore');
var fs = require('fs');
// Haha, this is so tricky. so we have a template for index.html to stick
// in the hashed JS and style files -- that template also contains
// templates used in the app. in order to avoid evaluating those
// templates, we change the regexes so we can effectively nest templates
_.templateSettings.interpolate = /\{\{(.+?)\}\}/g;
_.templateSettings.escape = /\{\{\{(.*?)\}\}\}/g;
_.templateSettings.evaluate = /\{\{-(.*?)\}\}/g;
// precompile for speed
var indexFile = fs.readFileSync('src/template.index.html').toString();
var indexTemplate = _.template(indexFile);
/**
* This is SUPER jank but I cant get the underscore templating to evaluate
* correctly with custom regexes, so I'm just going to use interpolate
* and define the strings here.
*/
var prodDependencies = [
'<script src="//cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.1/es5-shim.min.js"></script>',
'<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>',
'<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>',
'<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>'
];
var devDependencies = [
'<script src="lib/jquery-1.8.0.min.js"></script>',
'<script src="lib/underscore-min.js"></script>',
'<script src="lib/raphael-min.js"></script>',
'<script src="lib/es5-shim.min.js"></script>'
];
/*global module:false*/
module.exports = function(grunt) {
// eventually have sound...?
grunt.registerTask('compliment', 'Stay motivated!', function() {
var compliments = grunt.config('compliment.compliments');
var index = Math.floor(Math.random() * compliments.length);
grunt.log.writeln(compliments[index]);
});
grunt.registerTask('lintStrings', 'Find if an INTL string doesnt exist', function() {
var child_process = require('child_process');
child_process.exec('node src/js/intl/checkStrings', function(err, output) {
grunt.log.writeln(output);
});
});
var buildIndex = function(config) {
grunt.log.writeln('Building index...');
// first find the one in here that we want
var buildFiles = fs.readdirSync('build');
var hashedMinFile;
if (buildFiles.length == 2) {
grunt.log.writeln('Assuming debug mode wanted');
hashedMinFile = 'bundle.js';
}
var jsRegex = /bundle\.min\.\w+\.js/;
_.each(buildFiles, function(jsFile) {
if (jsRegex.test(jsFile)) {
if (hashedMinFile) {
throw new Error('more than one hashed file: ' + jsFile + hashedMinFile);
}
hashedMinFile = jsFile;
}
});
if (!hashedMinFile) { throw new Error('no hashed min file found!'); }
grunt.log.writeln('Found hashed js file: ' + hashedMinFile);
var styleRegex = /main\.\w+\.css/;
var hashedStyleFile;
_.each(buildFiles, function(styleFile) {
if (styleRegex.test(styleFile)) {
if (hashedStyleFile) {
throw new Error('more than one hashed style: ' + styleFile + hashedStyleFile);
}
hashedStyleFile = styleFile;
}
});
if (!hashedStyleFile) { throw new Error('no style found'); }
grunt.log.writeln('Found hashed style file: ' + hashedStyleFile);
// output these filenames to our index template
var outputIndex = indexTemplate({
jsFile: hashedMinFile,
styleFile: hashedStyleFile,
jsDependencies: config.isProd ?
prodDependencies.join("\n") :
devDependencies.join("\n")
});
fs.writeFileSync('index.html', outputIndex);
};
grunt.registerTask('buildIndex', 'stick in hashed resources', buildIndex.bind(null, {isProd: true}));
grunt.registerTask('buildIndexDev', 'stick in hashed resources', buildIndex.bind(null, {isProd: false}));
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jshint: {
all: [
'Gruntfile.js',
'__tests__/*.spec.js',
'src/js/**/*.js',
'src/js/**/**/*.js',
'src/levels/**/*.js'
],
options: {
ignores: [
'src/js/**/*.ios.js',
'src/js/native_react_views/*.js'
],
curly: true,
// sometimes triple equality is just redundant and unnecessary
eqeqeq: false,
// i know my regular expressions
regexp: false,
// i think it's super weird to not use new on a constructor
nonew: false,
// these latedefs are just annoying -- no pollution of global scope
latedef: false,
// use this in mocks
forin: false,
// This gets annoying
globalstrict: false,
// for use strict warnings
node: true,
///////////////////////////////
// All others are true
//////////////////////////////
immed: true,
newcap: true,
noarg: true,
bitwise: true,
sub: true,
undef: true,
unused: false,
trailing: true,
devel: true,
jquery: true,
nonstandard: true,
boss: true,
eqnull: true,
browser: true,
debug: true,
reporterOutput: '',
globals: {
casper: true,
Raphael: true,
require: true,
console: true,
describe: true,
expect: true,
it: true,
runs: true,
waitsFor: true,
exports: true,
module: true,
prompt: true,
process: true
}
},
},
compliment: {
compliments: [
"Wow peter great work!",
"Such a professional dev environment",
"Can't stop the TRAIN",
"git raging"
]
},
hash: {
options: {
mapping: ''
},
js: {
src: 'build/bundle.min.js',
dest: 'build/'
},
css: {
src: 'src/style/main.css',
dest: 'build/'
}
},
watch: {
files: '<config:lint.files>',
tasks: 'watching'
},
uglify: {
build: {
src: ['build/bundle.js'],
dest: 'build/bundle.min.js'
}
},
clean: ['build/*'],
shell: {
gitAdd: {
command: 'git add build/'
}
},
jasmine_node: {
projectRoot: './__tests__/',
forceExit: true,
verbose: true,
requirejs: false
},
env: {
prod: {
NODE_ENV: 'production',
},
},
browserify: {
options: {
transform: [require('grunt-react').browserify]
},
dist: {
files: {
'build/bundle.js': [
'src/**/*.js',
'src/**/*.jsx'
]
}
}
}
});
// all my npm helpers
grunt.loadNpmTasks('grunt-jsxhint');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-hash');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-shell-spawn');
grunt.loadNpmTasks('grunt-jasmine-node');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-react');
grunt.loadNpmTasks('grunt-env');
grunt.registerTask('build',
['clean', 'env', 'browserify', 'uglify', 'hash', 'buildIndex', 'shell:gitAdd', 'jasmine_node', 'jshint', 'lintStrings', 'compliment']
);
grunt.registerTask('lint', ['jshint', 'compliment']);
grunt.registerTask('fastBuild', ['clean', 'browserify', 'hash', 'buildIndexDev', 'jshint']);
grunt.registerTask('watching', ['fastBuild', 'jasmine_node', 'jshint', 'lintStrings']);
grunt.registerTask('default', ['build']);
grunt.registerTask('test', ['jasmine_node']);
grunt.registerTask('casperTest', ['shell:casperTest']);
};

View file

@ -1,8 +1,9 @@
# LearnGitBranching
[![Build Status](https://travis-ci.org/pcottle/learnGitBranching.svg?branch=master)](https://travis-ci.org/pcottle/learnGitBranching)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?)](https://github.com/pcottle/learnGitBranching/pulls)
LearnGitBranching is a git repository visualizer, sandbox, and series of educational tutorials and challenges. Its primary purpose is to help developers understand git through the power of visualization (something that's absent when working on the command line).
LearnGitBranching is a git repository visualizer, sandbox, and a series of educational tutorials and challenges. Its primary purpose is to help developers understand git through the power of visualization (something that's absent when working on the command line). This is achieved through a game with different levels to get acquainted with the different git commands.
You can input a variety of commands into LearnGitBranching (LGB) -- as commands are processed, the nearby commit tree will dynamically update to reflect the effects of each command:
@ -11,7 +12,7 @@ You can input a variety of commands into LearnGitBranching (LGB) -- as commands
This visualization combined with tutorials and "levels" can help both beginners and intermediate developers polish their version control skills. A quick demo is available here:
https://pcottle.github.com/learnGitBranching/?demo
Or you can launch the application normally here:
Or, you can launch the application normally here:
https://pcottle.github.com/learnGitBranching/
### Sandbox Mode
@ -69,34 +70,73 @@ Thus, if you build the app locally, all you have to do in order to run the app i
## Building yourself / Contributing Functionality
For contributing core functionality in the app, you'll probably want to test your changes
at least once before submitting a pull request. That means you'll need the "Grunt.js" build tool to build the app:
at least once before submitting a pull request. That means you'll need the "gulp.js" build tool to build the app:
https://gruntjs.com/getting-started
https://gulpjs.com/docs/en/getting-started/quick-start
You'll also need `npm` to download all the dependencies of the project.
You'll also need `yarn` to download all the dependencies of the project.
The general workflow / steps are below:
```
```bash
git clone <your fork of the repo>
cd learnGitBranching
npm install # to install all the node modules I depend on
yarn install
git checkout -b newAwesomeFeature
vim ./src/js/git/index.js # some changes
grunt fastBuild # skips tests and linting, faster build
yarn gulp fastBuild # skips tests and linting, faster build
# after building you can open up your browser to the index.html
# file generated and see your changes
vim ./src/js/git/index.js # more changes
grunt build # runs tests and lint
yarn gulp build # runs tests and lint
git commit -am "My new sweet feature!"
git push
# go online and request a pull
```
Alternatively, you can also build and run the app in a pre-configured online workspace:
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/pcottle/learnGitBranching/blob/master/src/js/git/index.js)
[//]: contributor-faces
<a href="https://github.com/pcottle"><img src="https://avatars0.githubusercontent.com/u/1135007?v=4" title="pcottle" width="80" height="80"></a>
<a href="https://github.com/Hongarc"><img src="https://avatars1.githubusercontent.com/u/19208123?v=4" title="Hongarc" width="80" height="80"></a>
<a href="https://github.com/twmht"><img src="https://avatars1.githubusercontent.com/u/1567200?v=4" title="twmht" width="80" height="80"></a>
<a href="https://github.com/JuhoKang"><img src="https://avatars1.githubusercontent.com/u/4745294?v=4" title="JuhoKang" width="80" height="80"></a>
<a href="https://github.com/sunshowers"><img src="https://avatars3.githubusercontent.com/u/180618?v=4" title="sunshowers" width="80" height="80"></a>
<a href="https://github.com/sPATROL"><img src="https://avatars0.githubusercontent.com/u/11875983?v=4" title="sPATROL" width="80" height="80"></a>
<a href="https://github.com/coyl"><img src="https://avatars1.githubusercontent.com/u/274452?v=4" title="coyl" width="80" height="80"></a>
<a href="https://github.com/alexeiberkov"><img src="https://avatars1.githubusercontent.com/u/4151345?v=4" title="alexeiberkov" width="80" height="80"></a>
<a href="https://github.com/aschrab"><img src="https://avatars1.githubusercontent.com/u/39620?v=4" title="aschrab" width="80" height="80"></a>
<a href="https://github.com/bcbcarl"><img src="https://avatars0.githubusercontent.com/u/135734?v=4" title="bcbcarl" width="80" height="80"></a>
<a href="https://github.com/ahonorat"><img src="https://avatars1.githubusercontent.com/u/5851945?v=4" title="ahonorat" width="80" height="80"></a>
<a href="https://github.com/nem75"><img src="https://avatars0.githubusercontent.com/u/1327785?v=4" title="nem75" width="80" height="80"></a>
<a href="https://github.com/eatdrinksleepcode"><img src="https://avatars0.githubusercontent.com/u/2099560?v=4" title="eatdrinksleepcode" width="80" height="80"></a>
<a href="https://github.com/nlehuby"><img src="https://avatars3.githubusercontent.com/u/919962?v=4" title="nlehuby" width="80" height="80"></a>
<a href="https://github.com/alexandear"><img src="https://avatars2.githubusercontent.com/u/3228886?v=4" title="alexandear" width="80" height="80"></a>
<a href="https://github.com/PanAeon"><img src="https://avatars3.githubusercontent.com/u/686076?v=4" title="PanAeon" width="80" height="80"></a>
<a href="https://github.com/donkirkby"><img src="https://avatars1.githubusercontent.com/u/1639148?v=4" title="donkirkby" width="80" height="80"></a>
<a href="https://github.com/lroellin"><img src="https://avatars1.githubusercontent.com/u/3150983?v=4" title="lroellin" width="80" height="80"></a>
<a href="https://github.com/ptsoccer"><img src="https://avatars1.githubusercontent.com/u/1102725?v=4" title="ptsoccer" width="80" height="80"></a>
<a href="https://github.com/jankeromnes"><img src="https://avatars2.githubusercontent.com/u/599268?v=4" title="jankeromnes" width="80" height="80"></a>
<a href="https://github.com/qiansen1386"><img src="https://avatars2.githubusercontent.com/u/1759658?v=4" title="qiansen1386" width="80" height="80"></a>
<a href="https://github.com/renderf0x"><img src="https://avatars1.githubusercontent.com/u/6155643?v=4" title="renderf0x" width="80" height="80"></a>
<a href="https://github.com/filipefilardi"><img src="https://avatars1.githubusercontent.com/u/7308241?v=4" title="filipefilardi" width="80" height="80"></a>
<a href="https://github.com/rebangm"><img src="https://avatars2.githubusercontent.com/u/1638136?v=4" title="rebangm" width="80" height="80"></a>
<a href="https://github.com/marcolivierarsenault"><img src="https://avatars2.githubusercontent.com/u/2634090?v=4" title="marcolivierarsenault" width="80" height="80"></a>
<a href="https://github.com/pengi"><img src="https://avatars0.githubusercontent.com/u/1087673?v=4" title="pengi" width="80" height="80"></a>
<a href="https://github.com/waldyrious"><img src="https://avatars2.githubusercontent.com/u/478237?v=4" title="waldyrious" width="80" height="80"></a>
<a href="https://github.com/tym-network"><img src="https://avatars1.githubusercontent.com/u/2879545?v=4" title="tym-network" width="80" height="80"></a>
<a href="https://github.com/zhyu"><img src="https://avatars1.githubusercontent.com/u/1728523?v=4" title="zhyu" width="80" height="80"></a>
<a href="https://github.com/mgarciaisaia"><img src="https://avatars1.githubusercontent.com/u/1190974?v=4" title="mgarciaisaia" width="80" height="80"></a>
<a href="https://github.com/olsza"><img src="https://avatars1.githubusercontent.com/u/12556170?v=4" title="Olsza" width="80" height="80"></a>
[//]: contributor-faces
## Helpful Folks
A big shoutout to these brave souls for extensively testing our sandbox and finding bugs and/or inconsistencies:
@ -122,7 +162,9 @@ And the following heroes for assisting in translating:
* Vasil Kulakov ("coyl") & Lyubov Agadjanyan ("shayenblue")
* Aliaksei Berkau ("alexeiberkov")
* Mizunashi Mana ("mizunashi-mana")
* Olsza
Also huge shoutout for everyone who has put up a pull request that was pulled! Check out the 30+ contributors we have in the [Contributors View](https://github.com/pcottle/learnGitBranching/graphs/contributors)
And everyone who has reported an issue that was successfully closed!

View file

@ -1,3 +1,5 @@
var Q = require('q');
var HeadlessGit = require('../src/js/git/headless').HeadlessGit;
var TreeCompare = require('../src/js/graph/treeCompare.js');
@ -26,65 +28,27 @@ var getHeadlessSummary = function(headless) {
var expectLevelAsync = function(headless, levelBlob) {
var command = levelBlob.solutionCommand;
if (command.indexOf('git rebase -i') !== -1) {
// dont do interactive rebase levels
// don't do interactive rebase levels
return;
}
var hasWarned = false;
var start;
runs(function() {
start = Date.now();
headless.sendCommand(command);
return headless.sendCommand(command).then(function() {
expect(compareLevelTree(headless, levelBlob)).toBeTruthy(
'Level "' + levelBlob['name']['en_US'] + '" should get solved'
);
});
waitsFor(function() {
var diff = (Date.now() - start);
if (diff > TIME - 10 && !hasWarned) {
hasWarned = true;
console.log('this goal tree', loadTree(levelBlob.goalTreeString));
console.log('not going to match with command', command);
console.log(getHeadlessSummary(headless));
}
var result = compareLevelTree(headless, levelBlob);
if (result) {
console.log('solved level ' + levelBlob.name.en_US);
}
return result;
}, 'trees should be equal', TIME);
};
var expectTreeAsync = function(command, expectedJSON, startJSON) {
var headless = new HeadlessGit();
var start = Date.now();
var haveReported = false;
if (startJSON) {
headless.gitEngine.loadTreeFromString(startJSON);
}
runs(function() {
headless.sendCommand(command);
return headless.sendCommand(command).then(function() {
expect(compareAnswer(headless, expectedJSON)).toBeTruthy();
});
waitsFor(function() {
var diff = (Date.now() - start);
if (diff > TIME - 40 && !haveReported) {
haveReported = true;
var expected = loadTree(expectedJSON);
console.log('not going to match', command);
console.log('expected\n>>>>>>>>\n', expected);
console.log('\n<<<<<<<<<<<\nactual', getHeadlessSummary(headless));
console.log('\n<<<<ORIGIN>>>>>\n');
if (expected.originTree) {
console.log('expected origin tree:');
console.log(expected.originTree);
console.log('\n=========\n');
console.log('actual origin tree');
console.log(getHeadlessSummary(headless).originTree);
}
console.log(expectedJSON);
console.log(JSON.stringify(getHeadlessSummary(headless)));
}
return compareAnswer(headless, expectedJSON);
}, 'trees should be equal', 500);
};
var expectLevelSolved = function(levelBlob) {
@ -95,6 +59,19 @@ var expectLevelSolved = function(levelBlob) {
expectLevelAsync(headless, levelBlob);
};
var runCommand = function(command, resultHandler) {
var headless = new HeadlessGit();
var deferred = Q.defer();
var msg = null;
return headless.sendCommand(command, deferred).then(function() {
return deferred.promise.then(function(commands) {
msg = commands[commands.length - 1].get('error').get('msg');
resultHandler(msg);
});
});
};
var TIME = 150;
// useful for throwing garbage and then expecting one commit
var ONE_COMMIT_TREE = '{"branches":{"master":{"target":"C2","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}';
@ -105,6 +82,6 @@ module.exports = {
TIME: TIME,
expectTreeAsync: expectTreeAsync,
expectLevelSolved: expectLevelSolved,
ONE_COMMIT_TREE: ONE_COMMIT_TREE
ONE_COMMIT_TREE: ONE_COMMIT_TREE,
runCommand: runCommand
};

View file

@ -1,279 +1,426 @@
var intl = require('../src/js/intl')
var base = require('./base');
var expectTreeAsync = base.expectTreeAsync;
var runCommand = base.runCommand;
describe('Git', function() {
it('Commits', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit',
base.ONE_COMMIT_TREE
);
});
it('handles commit options', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git commit --amend;',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22master%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('throws with bad arg options', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit foo; git commit -am -m; git commit -am -a; git commit -am "hi" "ho"; git commit',
base.ONE_COMMIT_TREE
);
});
it('handles lower case branch options', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch banana c0; git commit; git checkout -b side banana; git branch -d banana;git branch -f another c1; git commit',
'{"branches":{"master":{"target":"C2","id":"master"},"side":{"target":"C3","id":"side"},"another":{"target":"C1","id":"another"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C0"],"id":"C3"}},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('handles branch options', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch banana C0; git commit; git checkout -b side banana; git branch -d banana;git branch -f another C1; git commit',
'{"branches":{"master":{"target":"C2","id":"master"},"side":{"target":"C3","id":"side"},"another":{"target":"C1","id":"another"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C0"],"id":"C3"}},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('does add', function() {
expectTreeAsync(
return expectTreeAsync(
'git add; git commit',
base.ONE_COMMIT_TREE
);
});
it('resets with all options', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit;git reset --soft HEAD~1;git reset --hard HEAD~1;gc;go C1;git reset --hard C3;',
'{"branches":{"master":{"target":"C3","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"C1","id":"HEAD"}}'
);
});
it('Checkouts', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b side',
'{"branches":{"master":{"target":"C1","id":"master"},"side":{"target":"C1","id":"side"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('Switches', function() {
return expectTreeAsync(
'git switch -c side',
'{"branches":{"master":{"target":"C1","id":"master"},"side":{"target":"C1","id":"side"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('Rebases', function() {
expectTreeAsync(
return expectTreeAsync(
'gc; git checkout -b side C1; gc; git rebase master',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22side%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%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%7D'
);
});
it('Interactive rebase', function() {
expectTreeAsync(
return expectTreeAsync(
'gc; git checkout -b side C1; gc; git rebase -i master --interactive-test',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22side%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%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%7D'
);
});
it('Interactive rebases with commit re-ordering', function() {
expectTreeAsync(
return expectTreeAsync(
'gc;gc;git rebase -i C0 --interactive-test C3,C1',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%27%22%2C%22id%22%3A%22master%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C1%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C1%27%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22id%22%3A%22HEAD%22%2C%22target%22%3A%22master%22%7D%7D'
);
});
it('Switch branch and execute interactive rebase', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch test;git rebase -i C0 test --interactive-test',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22test%22%3A%7B%22target%22%3A%22C1%27%22%2C%22id%22%3A%22test%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%22C1%27%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%27%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22id%22%3A%22HEAD%22%2C%22target%22%3A%22test%22%7D%7D'
);
});
it('Reverts', function() {
expectTreeAsync(
return expectTreeAsync(
'git revert HEAD',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%27%22%2C%22id%22%3A%22master%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%22C1%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C1%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('Merges', function() {
expectTreeAsync(
return expectTreeAsync(
'gc; git checkout -b side C1; gc; git merge master',
'{"branches":{"master":{"target":"C2","id":"master"},"side":{"target":"C4","id":"side"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"}},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('Resets', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git reset HEAD~1',
'{"branches":{"master":{"target":"C1","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('Branches', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side C0',
'{"branches":{"master":{"target":"C1","id":"master"},"side":{"target":"C0","id":"side"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('Branches lowercase', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side c0',
'{"branches":{"master":{"target":"C1","id":"master"},"side":{"target":"C0","id":"side"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('Deletes branches', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side; git branch -d side',
'{"branches":{"master":{"target":"C1","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('Ammends commits', function() {
expectTreeAsync(
it('Amends commits', function() {
return expectTreeAsync(
'git commit --amend',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%27%22%2C%22id%22%3A%22master%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%22C1%27%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('Cherry picks', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b side C0; gc; git cherry-pick C11; git cherry-pick C1',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C1%27%22%2C%22id%22%3A%22side%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%22C2%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C1%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C1%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22side%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('Range operator is not supported', function() {
return expectTreeAsync(
'git checkout -b side C0; git cherry-pick C1..C0',
'{"branches":{"master":{"target": "C1","id": "master"},"side":{"target":"C0","id": "side"}},"commits":{"C0":{"parents":[],"id": "C0","rootCommit": true},"C1":{"parents":["C0"],"id": "C1"}},"HEAD":{"id": "HEAD","target":"side"}}'
);
});
it('Forces branches', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b side; git branch -f side C0',
'{"branches":{"master":{"target":"C1","id":"master"},"side":{"target":"C0","id":"side"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('Rebases only new commits to destination', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b side C0; gc; gc;git cherry-pick C1;git rebase master',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22side%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%22C2%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C1%27%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C1%27%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%27%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%27%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%7D'
);
});
it('checks out after a rebase', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git checkout -b bugFix C1; git commit; git rebase master;git checkout master',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22master%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22bugFix%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%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'
);
});
it('switches after a rebase ', function() {
return expectTreeAsync(
'git commit; git switch -c bugFix C1; git commit; git rebase master;git switch master',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22master%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22bugFix%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%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'
);
});
it('checks out after an interactive rebase', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git checkout -b bugFix C1; git commit; git rebase -i master --interactive-test;git checkout master',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22master%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22bugFix%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%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'
);
});
it('solves merging level', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b bugFix;git commit;git checkout master;git commit;git merge bugFix',
'{"branches":{"master":{"target":"C1","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}'
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C4%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22bugFix%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C2%22%2C%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('solves rebase level', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b bugFix;git commit;git checkout master;git commit;git checkout bugFix;git rebase master',
'{"branches":{"master":{"target":"C1","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}'
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C3%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22bugFix%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22bugFix%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('solves rebase level with interactive rebase', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b bugFix;git commit;git checkout master;git commit;git checkout bugFix;git rebase -i master --interactive-test',
'{"branches":{"master":{"target":"C1","id":"master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}'
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C3%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22bugFix%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22bugFix%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('does a whole bunch of crazy merging', function() {
expectTreeAsync(
return expectTreeAsync(
'gc;go -b side C1;gc;git merge master;go -b bug master;gc;go -b wut C3;git rebase bug;go side;git rebase wut;gc;git rebase wut;git merge C4;go master;git rebase side;go C6;git merge C3\';gb -f wut C8;go bug;git rebase wut',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C7%22%2C%22id%22%3A%22master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C7%22%2C%22id%22%3A%22side%22%7D%2C%22bug%22%3A%7B%22target%22%3A%22C8%22%2C%22id%22%3A%22bug%22%7D%2C%22wut%22%3A%7B%22target%22%3A%22C8%22%2C%22id%22%3A%22wut%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C2%22%2C%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C4%22%5D%2C%22id%22%3A%22C6%22%7D%2C%22C6%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C6%27%22%7D%2C%22C7%22%3A%7B%22parents%22%3A%5B%22C4%22%2C%22C6%27%22%5D%2C%22id%22%3A%22C7%22%7D%2C%22C8%22%3A%7B%22parents%22%3A%5B%22C3%27%22%2C%22C6%22%5D%2C%22id%22%3A%22C8%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22bug%22%2C%22id%22%3A%22HEAD%22%7D%7D'
);
});
it('if no-ff is specified, will always make a merge commit', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; go -b side HEAD~1; git commit; git merge master; go master; git merge side --no-ff',
'{"branches":{"master":{"target":"C5","id":"master","remoteTrackingBranchID":null},"side":{"target":"C4","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"},"C5":{"parents":["C2","C4"],"id":"C5"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('makes a tag', function() {
expectTreeAsync(
return expectTreeAsync(
'git tag v1',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{"v1":{"target":"C1","id":"v1","type":"tag"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('makes a tag and removes a tag', function() {
return expectTreeAsync(
'git tag v1; git tag -d v1',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('makes a tag on another ref', function() {
expectTreeAsync(
return expectTreeAsync(
'git tag v1 C0',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{"v1":{"target":"C0","id":"v1","type":"tag"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('doesnt make a tag if ref doesnt resolve', function() {
expectTreeAsync(
it('doesn\'t make a tag if ref doesn\'t resolve', function() {
return expectTreeAsync(
'git tag v1 foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('makes tag with relative ref and etc', function() {
expectTreeAsync(
return expectTreeAsync(
'git tag v1 HEAD~1',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{"v1":{"target":"C0","id":"v1","type":"tag"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('makes tag with 3 letters', function() {
expectTreeAsync(
return expectTreeAsync(
'git tag foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{"foo":{"target":"C1","id":"foo","type":"tag"}},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('does not make tag if ref does not resolve', function() {
expectTreeAsync(
return expectTreeAsync(
'git tag foo banana',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('should respect second command for -B option', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git checkout -B side C1',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"side":{"target":"C1","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"side","id":"HEAD"}}'
);
});
it('will throw error if bad commits given to interactive test', function() {
expectTreeAsync(
return expectTreeAsync(
'gc; git rebase HEAD~2 -i --interactive-test C2,C100; gc',
'{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
it('can handle slashes and dashes in branch names but doesnt allow o/', function() {
expectTreeAsync(
it('can handle slashes and dashes in branch names but doesn\'t allow o/', function() {
return expectTreeAsync(
'git branch foo/bar; git commit; git checkout foo/bar; gc; go master; git merge foo/bar; go foo/bar; git checkout -b bar-baz; git commit; git branch o/foo',
'{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null},"foo/bar":{"target":"C3","id":"foo/bar","remoteTrackingBranchID":null},"bar-baz":{"target":"C5","id":"bar-baz","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"},"C5":{"parents":["C3"],"id":"C5"}},"tags":{},"HEAD":{"target":"bar-baz","id":"HEAD"}}'
);
});
it('the regex allows for multiple dashes but not in a row', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch foo-bar-banana-baz; gc; git branch foo----bar//baz',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"foo-bar-b":{"target":"C1","id":"foo-bar-b","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}'
);
});
});
describe('RevList', function() {
it('requires at least 1 argument', function() {
return runCommand('git rev-list', function(commandMsg) {
expect(commandMsg).toEqual(intl.str(
'git-error-args-few',
{
lower: 1,
what: 'with git rev-list'
}
));
});
});
describe('supports', function() {
var SETUP = 'git co -b left C0; gc; git merge master; git co -b right C0; gc; git merge master; git co -b all left; git merge right; ';
it('single included revision', function() {
return runCommand(SETUP + 'git rev-list all', function(commandMsg) {
expect(commandMsg).toBe('C6\nC5\nC4\nC3\nC2\nC1\nC0\n');
});
});
it('single excluded revision', function() {
return runCommand(SETUP + 'git rev-list all ^right', function(commandMsg) {
expect(commandMsg).toBe('C6\nC3\nC2\n');
});
});
it('multiple included revisions', function() {
return runCommand(SETUP + 'git rev-list right left', function(commandMsg) {
expect(commandMsg).toBe('C5\nC4\nC3\nC2\nC1\nC0\n');
});
});
it('multiple excluded revisions', function() {
return runCommand(SETUP + 'git rev-list all ^right ^left', function(commandMsg) {
expect(commandMsg).toBe('C6\n');
});
});
it('range between branches', function() {
return runCommand(SETUP + 'git rev-list left..right', function(commandMsg) {
expect(commandMsg).toBe('C5\nC4\n');
});
});
it('range between commits', function() {
return runCommand(SETUP + 'git rev-list C3..C5', function(commandMsg) {
expect(commandMsg).toBe('C5\nC4\n');
});
});
});
});
describe('Log supports', function() {
var SETUP = 'git co -b left C0; gc; git merge master; git co -b right C0; gc; git merge master; git co -b all left; git merge right; ';
it('implied HEAD', function() {
return runCommand(SETUP + '; git co right; git log', function(commandMsg) {
expect(commandMsg).toContain('Commit: C0\n');
expect(commandMsg).toContain('Commit: C1\n');
expect(commandMsg).not.toContain('Commit: C2\n');
expect(commandMsg).not.toContain('Commit: C3\n');
expect(commandMsg).toContain('Commit: C4\n');
expect(commandMsg).toContain('Commit: C5\n');
expect(commandMsg).not.toContain('Commit: C6\n');
});
});
it('single included revision', function() {
return runCommand(SETUP + 'git log right', function(commandMsg) {
expect(commandMsg).toContain('Commit: C0\n');
expect(commandMsg).toContain('Commit: C1\n');
expect(commandMsg).not.toContain('Commit: C2\n');
expect(commandMsg).not.toContain('Commit: C3\n');
expect(commandMsg).toContain('Commit: C4\n');
expect(commandMsg).toContain('Commit: C5\n');
expect(commandMsg).not.toContain('Commit: C6\n');
});
});
it('single excluded revision', function() {
return runCommand(SETUP + 'git log all ^right', function(commandMsg) {
expect(commandMsg).not.toContain('Commit: C0\n');
expect(commandMsg).not.toContain('Commit: C1\n');
expect(commandMsg).toContain('Commit: C2\n');
expect(commandMsg).toContain('Commit: C3\n');
expect(commandMsg).not.toContain('Commit: C4\n');
expect(commandMsg).not.toContain('Commit: C5\n');
expect(commandMsg).toContain('Commit: C6\n');
});
});
it('multiple included revisions', function() {
return runCommand(SETUP + 'git log right left', function(commandMsg) {
expect(commandMsg).toContain('Commit: C0\n');
expect(commandMsg).toContain('Commit: C1\n');
expect(commandMsg).toContain('Commit: C2\n');
expect(commandMsg).toContain('Commit: C3\n');
expect(commandMsg).toContain('Commit: C4\n');
expect(commandMsg).toContain('Commit: C5\n');
expect(commandMsg).not.toContain('Commit: C6\n');
});
});
it('multiple excluded revisions', function() {
return runCommand(SETUP + 'git log all ^right ^left', function(commandMsg) {
expect(commandMsg).not.toContain('Commit: C0\n');
expect(commandMsg).not.toContain('Commit: C1\n');
expect(commandMsg).not.toContain('Commit: C2\n');
expect(commandMsg).not.toContain('Commit: C3\n');
expect(commandMsg).not.toContain('Commit: C4\n');
expect(commandMsg).not.toContain('Commit: C5\n');
expect(commandMsg).toContain('Commit: C6\n');
});
});
});
});

View file

@ -1,16 +1,14 @@
var base = require('./base');
describe('GitEngine Levels', function() {
it('solves levels', function() {
var sequences = require('../src/levels/index').levelSequences;
Object.keys(sequences).forEach(function(sequenceKey) {
var levels = sequences[sequenceKey];
Object.keys(levels).forEach(function(index) {
var levelBlob = levels[index];
console.log('testing level', levelBlob.name.en_US);
it('solves level ' + levelBlob['name']['en_US'] + ' in sequence ' + sequenceKey, function() {
base.expectLevelSolved(levelBlob);
});
}.bind(this));
});
});
});

View file

@ -4,7 +4,7 @@ var expectTreeAsync = base.expectTreeAsync;
describe('Mercurial', function() {
var assert = function(msg, command, tree) {
it(msg, function() {
expectTreeAsync(command, tree);
return expectTreeAsync(command, tree);
});
};
@ -63,4 +63,3 @@ describe('Mercurial', function() {
);
});

View file

@ -3,280 +3,280 @@ var expectTreeAsync = base.expectTreeAsync;
describe('Git Remotes', function() {
it('clones', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone',
'{"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":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('does fake teamwork', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork',
'{"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"}}}'
);
});
it('does fake teamwork and then fetches', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git fetch',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/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"},"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"}}}'
);
});
it('pulls', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git fakeTeamwork; git pull',
'{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C3","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls with rebase', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git fakeTeamwork; git pull --rebase',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%2C%22localBranchesThatTrackThis%22%3Anull%7D%2C%22o/master%22%3A%7B%22target%22%3A%22C3%22%2C%22id%22%3A%22o/master%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3A%5B%22master%22%5D%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%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%22%2C%22id%22%3A%22master%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%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D'
);
});
it('pushes', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git push',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/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"},"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"}}}'
);
});
it('pulls and then pushes', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git fakeTeamwork; git pull; git push',
'{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C4","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C3":{"parents":["C1"],"id":"C3"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C2","C3"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls with rebase and then pushes', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git fakeTeamwork; git pull --rebase; git push',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%2C%22localBranchesThatTrackThis%22%3Anull%7D%2C%22o/master%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22o/master%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3A%5B%22master%22%5D%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%2C%22originTree%22%3A%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22master%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%27%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D'
);
});
it('clones with many branches', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch bugFix; git clone',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"bugFix":{"target":"C1","id":"bugFix","remoteTrackingBranchID":"o/bugFix"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/bugFix":{"target":"C1","id":"o/bugFix","remoteTrackingBranchID":null}},"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},"bugFix":{"target":"C1","id":"bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('clones with a merge commit, does teamwork, fetches', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch bugFix; git commit; git checkout bugFix; git commit; git merge master; git clone; git fakeTeamwork bugFix 2',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"bugFix":{"target":"C4","id":"bugFix","remoteTrackingBranchID":"o/bugFix"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"o/bugFix":{"target":"C4","id":"o/bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"}},"HEAD":{"target":"bugFix","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"bugFix":{"target":"C6","id":"bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C2","C3"],"id":"C4"},"C5":{"parents":["C4"],"id":"C5"},"C6":{"parents":["C5"],"id":"C6"}},"HEAD":{"target":"bugFix","id":"HEAD"}}}'
);
});
it('only fetches one branch if specified', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch bugFix; git clone; git fakeTeamwork bugFix; git fakeTeamwork; git fetch origin bugFix',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"bugFix":{"target":"C1","id":"bugFix","remoteTrackingBranchID":"o/bugFix"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/bugFix":{"target":"C2","id":"o/bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":null},"bugFix":{"target":"C2","id":"bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('checks all branches for fetching', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch bugFix; git clone; git fakeTeamwork; git fetch',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"bugFix":{"target":"C1","id":"bugFix","remoteTrackingBranchID":"o/bugFix"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"o/bugFix":{"target":"C1","id":"o/bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"bugFix":{"target":"C1","id":"bugFix","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls with nothing and then commits', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git pull; git commit',
'{"branches":{"master":{"target":"C2","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"},"C2":{"parents":["C1"],"id":"C2"}},"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('pulls from different remote tracking branches nad merges', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side; git clone; git fakeTeamwork side;git commit; git pull origin side;git pull;git fakeTeamwork master;git pull',
'{"branches":{"master":{"target":"C6","id":"master","remoteTrackingBranchID":"o/master"},"side":{"target":"C1","id":"side","remoteTrackingBranchID":"o/side"},"o/master":{"target":"C5","id":"o/master","remoteTrackingBranchID":null},"o/side":{"target":"C2","id":"o/side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C3":{"parents":["C1"],"id":"C3"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C2","C3"],"id":"C4"},"C5":{"parents":["C1"],"id":"C5"},"C6":{"parents":["C4","C5"],"id":"C6"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C5","id":"master","remoteTrackingBranchID":null},"side":{"target":"C2","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C5":{"parents":["C1"],"id":"C5"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls with rebase from different remote tracking', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side; git clone; git fakeTeamwork side;git commit; git pull origin side --rebase',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22side%22%2C%22remoteTrackingBranchID%22%3A%22o/side%22%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/side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22o/side%22%2C%22remoteTrackingBranchID%22%3Anull%2C%22localBranchesThatTrackThis%22%3A%5B%22side%22%5D%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%22master%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%22side%22%3A%7B%22target%22%3A%22C2%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22side%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D'
);
});
it('pushes to another remote', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side; git clone;git commit; git push origin HEAD:side',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"side":{"target":"C1","id":"side","remoteTrackingBranchID":"o/side"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/side":{"target":"C2","id":"o/side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"side":{"target":"C2","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pushes to tracking remote', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch side; git clone;git commit;git push; go side; git commit; git push',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"side":{"target":"C3","id":"side","remoteTrackingBranchID":"o/side"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"o/side":{"target":"C3","id":"o/side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"side","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"side":{"target":"C3","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('sets tracking when checking out remote branch', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git checkout -b side o/master;git fakeTeamwork;git pull',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["master","side"]},"side":{"target":"C2","id":"side","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"side","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"}}}'
);
});
it('also sets tracking when just branching', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; gb side o/master',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null,"localBranchesThatTrackThis":["master","side"]},"side":{"target":"C1","id":"side","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('can push with colon refspec', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; gc; git checkout -b foo HEAD~1; git push origin master:master',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"foo","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"}}}'
);
});
it('can delete branches with colon refspec', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch foo; git clone; git push origin :foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null},"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":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pushes new branch onto server', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git push origin master:foo',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C2","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('does not push for HEAD', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git checkout C2; git push',
'{"branches":{"master":{"target":"C2","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"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"C2","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('does push for HEAD as a source though to a new branch', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git checkout C2; git push origin HEAD:foo',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C2","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"C2","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('but it cant delete master on remote', function() {
expectTreeAsync(
return expectTreeAsync(
'git branch foo; git clone; git push origin :master',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":"o/foo"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null}},"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},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('will prune the origin tree when deleting branches', function() {
expectTreeAsync(
return expectTreeAsync(
'git checkout -b foo; git commit; git clone; git push origin :foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"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"}}}'
);
});
it('will not push to a remote if the local ref does not exist', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git push origin foo',
'{"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":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('will push to the remote branch IF IT has tracking', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git checkout -b foo o/master; git commit; git push',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"foo","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"}}}'
);
});
it('will push to a new remote branch if no tracking is set up', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git checkout -b foo; git commit; git push',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":"o/foo"},"o/foo":{"target":"C2","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"foo","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('will push to the remote tracking branch WHILE NOT on branch if it is set up', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git checkout -b foo o/master; git commit; go master; git push origin foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"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"}}}'
);
});
it('will not fetch if ref does not exist on remote', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git fetch foo:master',
'{"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"}}}'
);
});
it('does not fetch if ref does not exist on remote with one arg', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git fetch foo',
'{"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"}}}'
);
});
it('validates branch names when fetching', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git fetch master:HEAD; git fetch master:f<>',
'{"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"}}}'
);
});
it('fetches only one remote if specified', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone;gc;git push origin master:banana;git fakeTeamwork banana;git fakeTeamwork master;git fetch origin banana',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/banana":{"target":"C3","id":"o/banana","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null},"banana":{"target":"C3","id":"banana","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C1"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('sets remote tracking', function() {
expectTreeAsync(
return 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(
return 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"}}}'
);
});
it('fetches with no args, explicit dest args, and with just one arg', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git fetch origin master:o/master;git fakeTeamwork;git fetch;git fakeTeamwork;git fetch origin master',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C4","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C3"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C3"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('doesnt fetch if out of sync, but will update explicit dest if specified', function() {
expectTreeAsync(
it('doesn\'t fetch if out of sync, but will update explicit dest if specified', function() {
return expectTreeAsync(
'git clone; git fakeTeamwork; go HEAD~1; git fetch origin master:master;go master; gc; go HEAD~1; git fakeTeamwork;git fetch origin master:master',
'{"branches":{"master":{"target":"C3","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"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"C2","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C2"],"id":"C4"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls to the right branch and destination', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git checkout -b side o/master;git fakeTeamwork;git pull origin master:o/master',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null},"side":{"target":"C2","id":"side","remoteTrackingBranchID":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"side","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"}}}'
);
});
it('correctly checks upstream when pushing to a remote where commits already exist but branch is not updated DAYAM dawg', function() {
expectTreeAsync(
return expectTreeAsync(
'git push origin master^:master',
'{"branches":{"master":{"target":"C9","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C8","id":"foo","remoteTrackingBranchID":"o/foo"},"o/master":{"target":"C5","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C5","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C1"],"id":"C4"},"C5":{"parents":["C2","C4"],"id":"C5"},"C6":{"parents":["C4"],"id":"C6"},"C7":{"parents":["C6"],"id":"C7"},"C8":{"parents":["C5","C7"],"id":"C8"},"C9":{"parents":["C5"],"id":"C9"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C5","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C5","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C1"],"id":"C4"},"C5":{"parents":["C2","C4"],"id":"C5"}},"HEAD":{"target":"master","id":"HEAD"}}}',
'{"branches":{"master":{"target":"C9","id":"master","remoteTrackingBranchID":"o/master"},"foo":{"target":"C8","id":"foo","remoteTrackingBranchID":"o/foo"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C5","id":"o/foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C1"],"id":"C4"},"C5":{"parents":["C2","C4"],"id":"C5"},"C6":{"parents":["C4"],"id":"C6"},"C7":{"parents":["C6"],"id":"C7"},"C8":{"parents":["C5","C7"],"id":"C8"},"C9":{"parents":["C5"],"id":"C9"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C5","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C1"],"id":"C4"},"C5":{"parents":["C2","C4"],"id":"C5"}},"HEAD":{"target":"master","id":"HEAD"}}}'
@ -284,98 +284,98 @@ describe('Git Remotes', function() {
});
it('correctly resolves source during git fetch with params', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git push origin master:foo; git fakeTeamwork foo 2; git fetch origin foo^:blah',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null},"blah":{"target":"C2","id":"blah","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C3","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"foo","id":"HEAD"}}}'
);
});
it('correctly makes a new branch during fetch despite nothing to download', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git push origin master:foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null}},"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},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('correctly resolves existing commits and updates', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git push origin master:foo; git fakeTeamwork foo 2; git fetch origin foo^:blah;go C0; git fetch origin foo^:master',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null},"blah":{"target":"C2","id":"blah","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"C0","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C3","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"foo","id":"HEAD"}}}'
);
});
it('doesnt let you fetch to master if you are checked out there', function() {
expectTreeAsync(
it('doesn\'t let you fetch to master if you are checked out there', function() {
return expectTreeAsync(
'git clone; git push origin master:foo; git fakeTeamwork foo 2; git fetch origin foo^:blah; git fetch foo:master',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","remoteTrackingBranchID":null},"blah":{"target":"C2","id":"blah","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C3","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"HEAD":{"target":"foo","id":"HEAD"}}}'
);
});
it('doesnt let you delete branches that dont exist', function() {
expectTreeAsync(
it('doesn\'t let you delete branches that don\'t exist', function() {
return expectTreeAsync(
'git clone; git push origin :foo',
'{"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":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls to a new branch and then merges in that branch', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git commit; git pull origin master:bar',
'{"branches":{"master":{"target":"C4","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"bar":{"target":"C2","id":"bar","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C3":{"parents":["C1"],"id":"C3"},"C2":{"parents":["C1"],"id":"C2"},"C4":{"parents":["C2","C3"],"id":"C4"}},"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"}}}'
);
});
it('makes a new branch from pull and doesnt bork', function() {
expectTreeAsync(
it('makes a new branch from pull and doesn\'t bork', function() {
return expectTreeAsync(
'git clone; git pull origin :bar',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"bar":{"target":"C1","id":"bar","remoteTrackingBranchID":null}},"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('makes the new branch on push in the right place', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git push origin master:foo',
'{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"o/foo":{"target":"C1","id":"o/foo","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},"foo":{"target":"C1","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('tracks remote with -u', function() {
expectTreeAsync(
return 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"}},"tags":{},"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"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('does not fetch if one arg is not branch ref', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork 2; git fetch origin master~1',
'{"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"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('creates the branch on the fly', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; go -b side; git push origin side',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C1","id":"o/master","remoteTrackingBranchID":null},"side":{"target":"C2","id":"side","remoteTrackingBranchID":"o/side"},"o/side":{"target":"C2","id":"o/side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"side","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C1","id":"master","remoteTrackingBranchID":null},"side":{"target":"C2","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('does not create the o/master branch on remote', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git push origin o/master',
'{"branches":{"master":{"target":"C2","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"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"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"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('pulls with rebase correctly in weird situation with no rebase to do', function() {
expectTreeAsync(
'git checkout -b side; git commit; git checkout master; git commit; git commit; git merge side; git commit; git clone; git checkout -b main master^^^; git rebase side; git rebase main master; git push;git pull --rebase',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C6%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22side%22%2C%22remoteTrackingBranchID%22%3A%22o/side%22%7D%2C%22o/master%22%3A%7B%22target%22%3A%22C6%22%2C%22id%22%3A%22o/master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22o/side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22o/side%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22main%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22main%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C2%22%2C%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C6%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C4%27%22%7D%2C%22C6%27%22%3A%7B%22parents%22%3A%5B%22C4%27%22%5D%2C%22id%22%3A%22C6%27%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%2C%22originTree%22%3A%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C6%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22side%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C2%22%2C%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C6%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D'
return expectTreeAsync(
'git checkout -b side; git commit; git checkout master; git commit; git commit; git merge side; git commit; git clone; git checkout -b otherMain master^^^; git rebase side; git rebase otherMain master; git push;git pull --rebase',
'%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C6%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3A%22o/master%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22side%22%2C%22remoteTrackingBranchID%22%3A%22o/side%22%7D%2C%22o/master%22%3A%7B%22target%22%3A%22C6%22%2C%22id%22%3A%22o/master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22o/side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22o/side%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22otherMain%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22otherMain%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C2%22%2C%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C6%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C4%27%22%7D%2C%22C6%27%22%3A%7B%22parents%22%3A%5B%22C4%27%22%5D%2C%22id%22%3A%22C6%27%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%2C%22originTree%22%3A%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C6%22%2C%22id%22%3A%22master%22%2C%22remoteTrackingBranchID%22%3Anull%7D%2C%22side%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22side%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%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C2%22%2C%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C5%22%5D%2C%22id%22%3A%22C6%22%7D%7D%2C%22tags%22%3A%7B%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D%7D'
);
});
it('pulls with rebase in other weird situation with just fast forward', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git fakeTeamwork; git pull --rebase',
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C2","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"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"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
@ -383,28 +383,28 @@ describe('Git Remotes', function() {
/* TODO -- enable this back when we have better async tree compare, it takes too long right now
it('will correctly resolve the dependency order of commits when fetching or pushing', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git commit; git commit; git checkout -b test C2; git commit; git checkout master; git push; git checkout master; git merge test; git commit; git push; git checkout test; git commit; git commit; git checkout -b feat1 master; git commit; git merge test; git checkout master; git merge test; git checkout feat1; git commit; git checkout master; git merge feat1; git push',
'{"branches":{"master":{"target":"C14","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C7","id":"o/master","remoteTrackingBranchID":null},"test":{"target":"C9","id":"test","remoteTrackingBranchID":null},"feat1":{"target":"C13","id":"feat1","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C3"],"id":"C4"},"C5":{"parents":["C2"],"id":"C5"},"C6":{"parents":["C4","C5"],"id":"C6"},"C7":{"parents":["C6"],"id":"C7"},"C8":{"parents":["C5"],"id":"C8"},"C9":{"parents":["C8"],"id":"C9"},"C10":{"parents":["C7"],"id":"C10"},"C11":{"parents":["C10","C9"],"id":"C11"},"C12":{"parents":["C7","C9"],"id":"C12"},"C13":{"parents":["C11"],"id":"C13"},"C14":{"parents":["C12","C13"],"id":"C14"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C7","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C2"],"id":"C3"},"C4":{"parents":["C3"],"id":"C4"},"C5":{"parents":["C2"],"id":"C5"},"C6":{"parents":["C4","C5"],"id":"C6"},"C7":{"parents":["C6"],"id":"C7"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});*/
it('uses git force to bypass upstream check', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone; git commit; git push; go C1; git branch -f master C1; go master; git commit; git commit; go C1; git checkout -b side; git commit; go master; git merge side; git push --force',
'{"branches":{"master":{"target":"C6","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C6","id":"o/master","remoteTrackingBranchID":null},"side":{"target":"C5","id":"side","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C3"],"id":"C4"},"C5":{"parents":["C1"],"id":"C5"},"C6":{"parents":["C4","C5"],"id":"C6"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C6","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C5":{"parents":["C1"],"id":"C5"},"C3":{"parents":["C1"],"id":"C3"},"C4":{"parents":["C3"],"id":"C4"},"C6":{"parents":["C4","C5"],"id":"C6"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('uses --push to delete commits', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git clone;git reset HEAD~1;git push --force',
'{"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"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"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"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);
});
it('uses --push to delete commits and can push again after', function() {
expectTreeAsync(
return expectTreeAsync(
'git commit; git clone;git reset HEAD~1;git push --force;git commit; git push ',
'{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":"o/master"},"o/master":{"target":"C3","id":"o/master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"target":"C3","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"},"C3":{"parents":["C1"],"id":"C3"}},"tags":{},"HEAD":{"target":"master","id":"HEAD"}}}'
);

View file

@ -3,7 +3,7 @@ var expectTreeAsync = base.expectTreeAsync;
describe('Git Remote simple', function() {
it('clones', function() {
expectTreeAsync(
return expectTreeAsync(
'git clone',
'{"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":"C1","id":"master","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"}}}'
);

View file

@ -49,9 +49,21 @@ describe('Tree Compare', function() {
);
});
it('compares with considering leftover branches', function() {
testMethod(
{
compareAllBranchesAndEnforceBranchCleanup: true,
},
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"foo","id":"HEAD"}}',
{
'{"branches":{"master":{"target":"C2","id":"master","remoteTrackingBranchID":null},"foo":{"target":"C2","id":"foo","remoteTrackingBranchID":null},"randoBran":{"target":"C2","id":"randoBran","remoteTrackingBranchID":null}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"tags":{},"HEAD":{"target":"foo","id":"HEAD"}}': false,
},
);
});
it('deep compares on origin tree', function() {
testMethod(
{}, // checked for all methods so this doesnt matter
{}, // checked for all methods so this doesn't matter
// state with originTree
'{"branches":{"master":{"target":"C1","id":"master"},"o/master":{"target":"C1","id":"o/master"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"}},"HEAD":{"target":"master","id":"HEAD"},"originTree":{"branches":{"master":{"remoteTrackingBranch":null,"remote":false,"target":"C1","id":"master","type":"branch"}},"commits":{"C0":{"type":"commit","parents":[],"author":"Peter Cottle","createTime":"Wed Jul 24 2013 09:58:50 GMT-0700 (PDT)","commitMessage":"Quick commit. Go Bears!","id":"C0","rootCommit":true},"C1":{"type":"commit","parents":["C0"],"author":"Peter Cottle","createTime":"Wed Jul 24 2013 09:58:50 GMT-0700 (PDT)","commitMessage":"Quick commit. Go Bears!","id":"C1"}},"HEAD":{"target":"master","id":"HEAD","type":"general ref"}}}',
{
@ -173,5 +185,3 @@ describe('Tree Compare', function() {
);
});
});

File diff suppressed because it is too large Load diff

BIN
assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

6
checkgit.sh Executable file
View file

@ -0,0 +1,6 @@
GIT_STATUS=$(git status --porcelain | wc -l )
if [[ GIT_STATUS -ne 0 ]]; then
echo "${1:-Source files were modified}"
git status
exit $GIT_STATUS
fi;

213
gulpfile.js Normal file
View file

@ -0,0 +1,213 @@
var { execSync } = require('child_process');
var { writeFileSync, readdirSync, readFileSync } = require('fs');
var glob = require('glob');
var _ = require('underscore');
var { src, dest, series, watch } = require('gulp');
var log = require('fancy-log');
var gHash = require('gulp-hash');
var gClean = require('gulp-clean');
var concat = require('gulp-concat');
var cleanCSS = require('gulp-clean-css');
var gTerser = require('gulp-terser');
var gJasmine = require('gulp-jasmine');
var { minify } = require('html-minifier');
var { SpecReporter } = require('jasmine-spec-reporter');
var gJshint = require('gulp-jshint');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var browserify = require('browserify');
var babelify = require('babelify');
_.templateSettings.interpolate = /\{\{(.+?)\}\}/g;
_.templateSettings.escape = /\{\{\{(.*?)\}\}\}/g;
_.templateSettings.evaluate = /\{\{-(.*?)\}\}/g;
// precompile for speed
var indexFile = readFileSync('src/template.index.html').toString();
var indexTemplate = _.template(indexFile);
var compliments = [
'Thanks to Hongarc for the modern and amazing gulp workflow!',
'I hope you all have a great day :)'
];
var compliment = (done) => {
var index = Math.floor(Math.random() * compliments.length);
log(compliments[index]);
done();
};
const lintStrings = (done) => {
execSync('node src/js/intl/checkStrings');
done();
};
var destDir = './build/';
var buildIndex = function(done) {
log('Building index...');
// first find the one in here that we want
var buildFiles = readdirSync(destDir);
var jsRegex = /bundle-[\.\w]+\.js/;
var jsFile = buildFiles.find(function(name) {
return jsRegex.exec(name);
});
if (!jsFile) {
throw new Error('no hashed min file found!');
}
log('Found hashed js file: ' + jsFile);
var styleRegex = /main-[\.\w]+\.css/;
var styleFile = buildFiles.find(function(name) {
return styleRegex.exec(name);
});
if (!styleFile) {
throw new Error('no hashed css file found!');
}
log('Found hashed style file: ' + styleFile);
// output these filenames to our index template
var outputIndex = indexTemplate({
jsFile,
styleFile,
});
if (process.env.NODE_ENV === 'production') {
outputIndex = minify(outputIndex, {
minifyJS: true,
collapseWhitespace: true,
processScripts: ['text/html'],
removeComments: true,
});
}
writeFileSync('index.html', outputIndex);
done();
};
var getBundle = function() {
return browserify({
entries: [...glob.sync('src/**/*.js'), ...glob.sync('src/**/*.jsx')],
debug: true,
})
.transform(babelify, { presets: ['@babel/preset-react'] })
.bundle()
.pipe(source('bundle.js'))
.pipe(buffer())
.pipe(gHash());
};
var clean = function () {
return src(destDir, { read: false, allowEmpty: true })
.pipe(gClean());
};
var jshint = function() {
return src([
'gulpfile.js',
'__tests__/',
'src/'
])
.pipe(gJshint())
.pipe(gJshint.reporter('default'));
};
var ifyBuild = function() {
return getBundle()
.pipe(dest(destDir));
};
var miniBuild = function() {
process.env.NODE_ENV = 'production';
return getBundle()
.pipe(gTerser())
.pipe(dest(destDir));
};
var style = function() {
var chain = src('src/style/*.css')
.pipe(concat('main.css'));
if (process.env.NODE_ENV === 'production') {
chain = chain.pipe(cleanCSS());
}
return chain.pipe(gHash())
.pipe(dest(destDir));
};
var jasmine = function() {
return src('__tests__/*.spec.js')
.pipe(gJasmine({
config: {
verbose: true,
random: false,
},
reporter: new SpecReporter(),
}));
};
var gitAdd = function(done) {
execSync('git add build/');
done();
};
var gitDeployMergeMaster = function(done) {
execSync('git checkout gh-pages && git merge master -m "merge master"');
done();
};
var gitDeployPushOrigin = function(done) {
execSync('git commit -am "rebuild for prod"; ' +
'git push origin gh-pages --force && ' +
'git branch -f trunk gh-pages && ' +
'git checkout master'
);
done();
};
var fastBuild = series(clean, ifyBuild, style, buildIndex, jshint);
var build = series(
clean,
miniBuild, style, buildIndex,
gitAdd, jasmine, jshint,
lintStrings, compliment
);
var deploy = series(
clean,
jasmine,
jshint,
gitDeployMergeMaster,
build,
gitDeployPushOrigin,
compliment
);
var lint = series(jshint, compliment);
var watching = function() {
return watch([
'gulpfile.js',
'__tests__/git.spec.js',
'src/js/**/*.js',
'src/js/**/**/*.js',
'src/levels/**/*.js'
], series([fastBuild , jasmine, jshint, lintStrings]));
};
module.exports = {
default: build,
lint,
fastBuild,
watching,
build,
test: jasmine,
deploy,
};

7
lib/es5-shim.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

10
lib/raphael-min.js vendored

File diff suppressed because one or more lines are too long

32
lib/underscore-min.js vendored
View file

@ -1,32 +0,0 @@
// Underscore.js 1.3.3
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function(){function r(a,c,d){if(a===c)return 0!==a||1/a==1/c;if(null==a||null==c)return a===c;a._chain&&(a=a._wrapped);c._chain&&(c=c._wrapped);if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return!1;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:0==a?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if("object"!=typeof a||"object"!=typeof c)return!1;for(var f=d.length;f--;)if(d[f]==a)return!0;d.push(a);var f=0,g=!0;if("[object Array]"==e){if(f=a.length,g=f==c.length)for(;f--&&(g=f in a==f in c&&r(a[f],c[f],d)););}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return!1;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,h)&&!f--)break;
g=!f}}d.pop();return g}var s=this,I=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,J=k.unshift,l=p.toString,K=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,L=Object.keys,t=Function.prototype.bind,b=function(a){return new m(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,
c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(A&&
a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,
c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,
a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&
(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){d=Math.floor(Math.random()*(f+1));b[f]=b[d];b[d]=a});return b};b.sortBy=function(a,c,d){var e=b.isFunction(c)?c:function(a){return a[c]};return b.pluck(b.map(a,function(a,b,c){return{value:a,criteria:e.call(d,a,b,c)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c===void 0?1:d===void 0?-1:c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};
j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,
0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,
e=[];a.length<3&&(c=true);b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=
i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<=
1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+d}return g};var H=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));H.prototype=a.prototype;var b=new H,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=
i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h=
g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));g?h=true:i=a.apply(d,e);j();g=true;return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments;d&&!e&&a.apply(f,g);clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));
return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&
c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=
function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"};
b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,
b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId=
function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape||
u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};
b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d,
this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);

264
npm-shrinkwrap.json generated
View file

@ -1,264 +0,0 @@
{
"name": "LearnGitBranching",
"version": "0.8.0",
"dependencies": {
"backbone": {
"version": "1.1.2",
"from": "backbone@*",
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.1.2.tgz",
"dependencies": {
"underscore": {
"version": "1.8.3",
"from": "underscore@>=1.5.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz"
}
}
},
"events": {
"version": "1.0.2",
"from": "events@*",
"resolved": "https://registry.npmjs.org/events/-/events-1.0.2.tgz"
},
"flux": {
"version": "2.0.1",
"from": "flux@*",
"resolved": "https://registry.npmjs.org/flux/-/flux-2.0.1.tgz"
},
"jquery": {
"version": "1.7.3",
"from": "jquery@~1.7.3",
"dependencies": {
"jsdom": {
"version": "0.2.19",
"from": "jsdom@~0.2.14",
"dependencies": {
"request": {
"version": "2.30.0",
"from": "request@2.x",
"dependencies": {
"qs": {
"version": "0.6.6",
"from": "qs@~0.6.0"
},
"json-stringify-safe": {
"version": "5.0.0",
"from": "json-stringify-safe@~5.0.0"
},
"forever-agent": {
"version": "0.5.0",
"from": "forever-agent@~0.5.0"
},
"node-uuid": {
"version": "1.4.1",
"from": "node-uuid@~1.4.0"
},
"mime": {
"version": "1.2.11",
"from": "mime@~1.2.9"
},
"tough-cookie": {
"version": "0.9.15",
"from": "tough-cookie@~0.9.15",
"dependencies": {
"punycode": {
"version": "1.2.3",
"from": "punycode@>=0.2.0"
}
}
},
"form-data": {
"version": "0.1.2",
"from": "form-data@~0.1.0",
"dependencies": {
"combined-stream": {
"version": "0.0.4",
"from": "combined-stream@~0.0.4",
"dependencies": {
"delayed-stream": {
"version": "0.0.5",
"from": "delayed-stream@0.0.5"
}
}
},
"async": {
"version": "0.2.9",
"from": "async@~0.2.9"
}
}
},
"tunnel-agent": {
"version": "0.3.0",
"from": "tunnel-agent@~0.3.0"
},
"http-signature": {
"version": "0.10.0",
"from": "http-signature@~0.10.0",
"dependencies": {
"assert-plus": {
"version": "0.1.2",
"from": "assert-plus@0.1.2"
},
"asn1": {
"version": "0.1.11",
"from": "asn1@0.1.11"
},
"ctype": {
"version": "0.5.2",
"from": "ctype@0.5.2"
}
}
},
"oauth-sign": {
"version": "0.3.0",
"from": "oauth-sign@~0.3.0"
},
"hawk": {
"version": "1.0.0",
"from": "hawk@~1.0.0",
"dependencies": {
"hoek": {
"version": "0.9.1",
"from": "hoek@0.9.x"
},
"boom": {
"version": "0.4.2",
"from": "boom@0.4.x"
},
"cryptiles": {
"version": "0.2.2",
"from": "cryptiles@0.2.x"
},
"sntp": {
"version": "0.2.4",
"from": "sntp@0.2.x"
}
}
},
"aws-sign2": {
"version": "0.5.0",
"from": "aws-sign2@~0.5.0"
}
}
},
"cssom": {
"version": "0.2.5",
"from": "cssom@0.2.x"
},
"cssstyle": {
"version": "0.2.9",
"from": "cssstyle@>=0.2.3",
"dependencies": {
"cssom": {
"version": "0.3.0",
"from": "cssom@0.3.x"
}
}
},
"contextify": {
"version": "0.1.6",
"from": "contextify@0.1.x",
"dependencies": {
"bindings": {
"version": "1.1.1",
"from": "bindings@*"
}
}
}
}
},
"htmlparser": {
"version": "1.7.6",
"from": "htmlparser@1.7.6"
},
"xmlhttprequest": {
"version": "1.4.2",
"from": "xmlhttprequest@~1.4.2"
},
"location": {
"version": "0.0.1",
"from": "location@0.0.1"
},
"navigator": {
"version": "1.0.1",
"from": "navigator@~1.0.1"
}
}
},
"markdown": {
"version": "0.4.0",
"from": "markdown@~0.4.0",
"dependencies": {
"nopt": {
"version": "1.0.10",
"from": "nopt@1",
"dependencies": {
"abbrev": {
"version": "1.0.4",
"from": "abbrev@1"
}
}
}
}
},
"object-assign": {
"version": "2.0.0",
"from": "object-assign@*",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.0.0.tgz"
},
"q": {
"version": "0.8.12",
"from": "q@~0.8.11"
},
"react": {
"version": "0.13.1",
"from": "react@*",
"resolved": "https://registry.npmjs.org/react/-/react-0.13.1.tgz",
"dependencies": {
"envify": {
"version": "3.4.0",
"from": "envify@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/envify/-/envify-3.4.0.tgz",
"dependencies": {
"through": {
"version": "2.3.6",
"from": "through@>=2.3.4 <2.4.0",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.6.tgz"
},
"jstransform": {
"version": "10.1.0",
"from": "jstransform@>=10.0.1 <11.0.0",
"resolved": "https://registry.npmjs.org/jstransform/-/jstransform-10.1.0.tgz",
"dependencies": {
"base62": {
"version": "0.1.1",
"from": "base62@0.1.1",
"resolved": "https://registry.npmjs.org/base62/-/base62-0.1.1.tgz"
},
"esprima-fb": {
"version": "13001.1001.0-dev-harmony-fb",
"from": "esprima-fb@13001.1001.0-dev-harmony-fb",
"resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-13001.1001.0-dev-harmony-fb.tgz"
},
"source-map": {
"version": "0.1.31",
"from": "source-map@0.1.31",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz",
"dependencies": {
"amdefine": {
"version": "0.1.0",
"from": "amdefine@>=0.0.4"
}
}
}
}
}
}
}
}
},
"underscore": {
"version": "1.4.4",
"from": "underscore@~1.4.3"
}
}
}

View file

@ -1,41 +1,52 @@
{
"name": "LearnGitBranching",
"version": "0.8.0",
"description": "An interactive git visualization to challenge and educate!",
"homepage": "https://learngitbranching.js.org",
"author": "Peter Cottle <petermcottle@gmail.com>",
"license": "MIT",
"scripts": {
"test": "grunt test"
"test": "gulp test"
},
"repository": {
"type": "git",
"url": "https://github.com/pcottle/learnGitBranching"
},
"devDependencies": {
"browserify": "^13.0.0",
"grunt": "~0.4.2",
"grunt-browserify": "^4.0.1",
"grunt-cli": "~0.1.11",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-uglify": "~0.2.7",
"grunt-env": "^0.4.4",
"grunt-hash": "~0.5.0",
"grunt-jasmine-node": "~0.1.0",
"grunt-jsxhint": "^0.5.0",
"grunt-react": "^0.12.1",
"grunt-shell-spawn": "~0.3.0",
"jasmine-node": "~1.12.0",
"@babel/core": "^7.4.8",
"@babel/preset-react": "^7.0.0",
"babelify": "^10.0.0",
"browserify": "^16.5.0",
"contributor-faces": "^1.0.2",
"fancy-log": "^1.3.3",
"glob": "^7.1.6",
"gulp": "^4.0.2",
"gulp-clean": "^0.4.0",
"gulp-clean-css": "^4.3.0",
"gulp-concat": "^2.6.1",
"gulp-hash": "^4.2.2",
"gulp-jasmine": "^4.0.0",
"gulp-jshint": "^2.1.0",
"gulp-terser": "^1.2.0",
"gulp-uglify": "^3.0.2",
"html-minifier": "^4.0.0",
"jasmine-spec-reporter": "^4.2.1",
"jshint": "^2.11.0",
"prompt": "^1.0.0",
"react-tools": "^0.13.1"
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0"
},
"dependencies": {
"backbone": "~1.1.2",
"events": "^1.0.2",
"flux": "^2.0.1",
"jquery": "~1.7.3",
"markdown": "~0.4.0",
"object-assign": "^2.0.0",
"q": "~0.8.11",
"react": "^0.13.1",
"backbone": "^1.4.0",
"flux": "^3.1.3",
"jquery": "^3.4.0",
"jquery-ui": "^1.12.1",
"marked": "^1.0.0",
"prop-types": "^15.7.2",
"q": "^1.5.1",
"raphael": "^2.1.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"underscore": "~1.4.3"
}
}

View file

@ -20,6 +20,12 @@ var GlobalStateActions = {
});
},
disableLevelInstructions: function() {
AppDispatcher.handleViewAction({
type: ActionTypes.DISABLE_LEVEL_INSTRUCTIONS,
});
},
changeFlipTreeY: function(flipTreeY) {
AppDispatcher.handleViewAction({
type: ActionTypes.CHANGE_FLIP_TREE_Y,

View file

@ -1,8 +1,9 @@
var Backbone = require('backbone');
var jQuery = require('jquery');
var EventEmitter = require('events').EventEmitter;
var React = require('react');
var ReactDOM = require('react-dom');
var assign = require('object-assign');
var util = require('../util');
var intl = require('../intl');
var LocaleStore = require('../stores/LocaleStore');
@ -11,7 +12,17 @@ var LocaleActions = require('../actions/LocaleActions');
/**
* Globals
*/
var events = assign(
Backbone.$ = jQuery;
// Bypass jasmine
if (util.isBrowser()) {
window.jQuery = jQuery;
window.$ = jQuery;
window.Raphael = require('raphael');
}
var events = Object.assign(
{},
EventEmitter.prototype,
{
@ -21,7 +32,7 @@ var events = assign(
}
}
);
// Allow unlimited listeners, so FF doesnt break
// Allow unlimited listeners, so FF doesn't break
events.setMaxListeners(0);
var commandUI;
var sandbox;
@ -86,8 +97,28 @@ var vcsModeRefresh = function(eventData) {
$('body').toggleClass('hgMode', !isGit);
};
var insertAlternateLinks = function(pageId) {
// For now pageId is null, which would link to the main page.
// In future if pageId is provided this method should link to a specific page
// The value of the hreflang attribute identifies the language (in ISO 639-1 format)
// and optionally a region (in ISO 3166-1 Alpha 2 format) of an alternate URL
var altLinks = LocaleStore.getSupportedLocales().map(function(langCode) {
var url = "https://learngitbranching.js.org/?locale=" + langCode;
return '<link rel="alternate" hreflang="'+langCode+'" href="' + url +'" />';
});
var defaultUrl = "https://learngitbranching.js.org/?locale=" + LocaleStore.getDefaultLocale();
altLinks.push('<link rel="alternate" hreflang="x-default" href="' + defaultUrl +'" />');
$('head').prepend(altLinks);
};
var intlRefresh = function() {
if (!window.$) { return; }
var countryCode = LocaleStore.getLocale().split("_")[0];
$("html").attr('lang', countryCode);
$("meta[http-equiv='content-language']").attr("content", countryCode);
$('span.intl-aware').each(function(i, el) {
var intl = require('../intl');
var key = $(el).attr('data-intl');
@ -145,7 +176,7 @@ var initRootEvents = function(eventBaton) {
var initDemo = function(sandbox) {
var params = util.parseQueryString(window.location.href);
// being the smart programmer I am (not), I dont include a true value on demo, so
// being the smart programmer I am (not), I don't include a true value on demo, so
// I have to check if the key exists here
var commands;
if (/(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent) || /android/i.test(navigator.userAgent)) {
@ -232,7 +263,7 @@ var initDemo = function(sandbox) {
}
if (params.hasOwnProperty('STARTREACT')) {
/*
React.render(
ReactDOM.render(
React.createElement(CommandView, {}),
document.getElementById(params['STARTREACT'])
);*/
@ -249,6 +280,8 @@ var initDemo = function(sandbox) {
tryLocaleDetect();
}
insertAlternateLinks();
if (params.command) {
var command = unescape(params.command);
sandbox.mainVis.customEvents.on('gitEngineReady', function() {
@ -294,11 +327,11 @@ function CommandUI() {
el: $('#commandLineBar')
});
React.render(
ReactDOM.render(
React.createElement(MainHelperBarView),
document.getElementById('helperBarMount')
);
React.render(
ReactDOM.render(
React.createElement(
CommandHistoryView,
{ commandCollection: this.commandCollection }
@ -328,4 +361,3 @@ exports.getLevelDropdown = function() {
};
exports.init = init;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var intl = require('../intl');
var Errors = require('../util/errors');
@ -16,7 +15,7 @@ var commandConfigs = {
var commands = {
execute: function(vcs, name, engine, commandObj) {
if (!commandConfigs[vcs][name]) {
throw new Error('i dont have a command for ' + name);
throw new Error('i don\'t have a command for ' + name);
}
var config = commandConfigs[vcs][name];
if (config.delegate) {
@ -34,7 +33,7 @@ var commands = {
if (result.multiDelegate) {
// we need to do multiple delegations with
// a different command at each step
_.each(result.multiDelegate, function(delConfig) {
result.multiDelegate.forEach(function(delConfig) {
// copy command, and then set opts
commandObj.setOptionsMap(delConfig.options || {});
commandObj.setGeneralArgs(delConfig.args || []);
@ -70,7 +69,7 @@ var commands = {
var displayName = config.displayName || name;
var thisMap = {};
// start all options off as disabled
_.each(config.options, function(option) {
(config.options || []).forEach(function(option) {
thisMap[option] = false;
});
optionMap[vcs][displayName] = thisMap;
@ -102,8 +101,10 @@ var commands = {
},
loop: function(callback, context) {
_.each(commandConfigs, function(commandConfig, vcs) {
_.each(commandConfig, function(config, name) {
Object.keys(commandConfigs).forEach(function(vcs) {
var commandConfig = commandConfigs[vcs];
Object.keys(commandConfig).forEach(function(name) {
var config = commandConfig[name];
callback(config, name, vcs);
});
});
@ -116,18 +117,21 @@ var parse = function(str) {
var options;
// see if we support this particular command
_.each(commands.getRegexMap(), function (map, thisVCS) {
_.each(map, function(regex, thisMethod) {
var regexMap = commands.getRegexMap();
Object.keys(regexMap).forEach(function (thisVCS) {
var map = regexMap[thisVCS];
Object.keys(map).forEach(function(thisMethod) {
var regex = map[thisMethod];
if (regex.exec(str)) {
vcs = thisVCS;
method = thisMethod;
// every valid regex has to have the parts of
// <vcs> <command> <stuff>
// because there are always two spaces
// because there are always two space-groups
// before our "stuff" we can simply
// split on spaces and grab everything after
// split on space-groups and grab everything after
// the second:
options = str.split(' ').slice(2).join(' ');
options = str.match(/('.*?'|".*?"|\S+)/g).slice(2);
}
});
});
@ -170,11 +174,8 @@ function CommandOptionParser(vcs, method, options) {
}
CommandOptionParser.prototype.explodeAndSet = function() {
// TODO -- this is ugly
// split on spaces, except when inside quotes
var exploded = this.rawOptions.match(/('.*?'|".*?"|\S+)/g) || [];
for (var i = 0; i < exploded.length; i++) {
var part = exploded[i];
for (var i = 0; i < this.rawOptions.length; i++) {
var part = this.rawOptions[i];
if (part.slice(0,1) == '-') {
// it's an option, check supportedMap
@ -187,7 +188,7 @@ CommandOptionParser.prototype.explodeAndSet = function() {
});
}
var next = exploded[i + 1];
var next = this.rawOptions[i + 1];
var optionArgs = [];
if (next && next.slice(0,1) !== '-') {
// only store the next argument as this

View file

@ -26,6 +26,7 @@ module.exports = {
SUBMIT_COMMAND: null,
CHANGE_LOCALE: null,
CHANGE_LOCALE_FROM_HEADER: null,
DISABLE_LEVEL_INSTRUCTIONS: null,
/**
* only dispatched when you actually
* solve the level, not ask for solution

View file

@ -1,16 +0,0 @@
var AppStyles = {
blueBackground: '#5cbcfc',
terminalBackground: '#424242',
terminalText: 'rgb(238, 238, 238)',
terminalHeader: '#EFEDEE',
terminalBorder: '#303030',
terminalFontFamily: 'Courier',
};
AppStyles.terminalTextStyle = {
color: AppStyles.terminalText,
fontFamily: AppStyles.terminalFontFamily,
fontWeight: 'bold',
};
module.exports = AppStyles;

View file

@ -1,19 +0,0 @@
var assign = require('object-assign');
var keyMirror = require('../util/keyMirror');
module.exports = keyMirror({
NUX: null,
LOADING: null,
SEQUENCE_SELECT: null,
LEVEL_SELECT: null,
});
module.exports.getRouteWithParams = function(id, params) {
return assign({id: id}, params);
};
module.exports.getRouteForID = function(id) {
return {
id: id,
};
};

View file

@ -49,6 +49,26 @@ exports.dialog = {
]
}
}],
'es_MX': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¿Estás seguro de que quieres ver la solución?',
'',
'¡Creo en ti! ¡Yo sé que puedes!'
]
}
}],
'es_ES': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¿Estás seguro de que quieres ver la solución?',
'',
'¡Creo en ti! ¡Ánimo!'
]
}
}],
'pt_BR': [{
type: 'ModalAlert',
options: {
@ -59,13 +79,23 @@ exports.dialog = {
]
}
}],
'gl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¿Queres ver a solución?',
'',
'Seguro que podes, ¡inténtao unha vez máis!'
]
}
}],
'fr_FR': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Êtes-vous sûr de vouloir voir la solution ?',
'',
'Je crois en vous ! Vous pouvez le faire'
'Je crois en vous ! Vous pouvez le faire !'
]
}
}],
@ -99,11 +129,51 @@ exports.dialog = {
type: 'ModalAlert',
options: {
markdowns: [
'## Впевнений, що хошеш побачити розв’язок?',
'## Впевнений, що хочеш побачити розв’язок?',
'',
'Я вірю в тебе! Ти впораєшся!'
]
}
}]
}],
'vi': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Bạn chắc là muốn xem đáp án chứ?',
'',
'Tôi tin ở bạn! Bạn có thể làm được!'
]
}
}],
'sl_SI': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Si prepričan, da hočeš videti rešitev?',
'',
'Verjamem vate! Maš ti to! Ali pač ne?'
]
}
}],
'pl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Czy na pewno chcesz zobaczyć rozwiązanie?',
'',
'Wierzę w Ciebie! Możesz to zrobić'
]
}
}],
'ta_IN': [{
type: 'ModalAlert',
options: {
markdowns: [
'## நீங்கள் நிச்சயமாக தீர்வை காண விரும்புகிறீர்களா?',
'',
'நான் உங்களால் அதை செய்ய முடியும் என நினைக்கிறேன்!'
]
}
}],
};

View file

@ -26,13 +26,13 @@ exports.dialog = {
'',
'So funktioniert\'s:',
'',
' * Stelle mit Git-Befehlen die Ausganssituation her',
' * Stelle mit Git-Befehlen die Ausgangssituation her',
' * Leg den Startpunkt mit ```define start``` fest',
' * Gib eine Abfolge von Git-Befehlen ein, welche die (optimale) Lösung darstellen',
' * Leg den Ziel-Baum mit ```define goal``` fest. Damit markierst du den Endpunkt der Lösung',
' * Gib einen Hinweis mittels ```define hint``` an, wenn du willst',
' * Änder den Namen mittels ```define name```',
' * Wenn du magst, erstelle einen schönene Einführungsdialog mit ```edit dialog```',
' * Wenn du magst, erstelle einen schönen Einführungsdialog mit ```edit dialog```',
' * Gib das Kommando ```finish``` ein um deinen Level als JSON auszugeben'
]
}
@ -94,6 +94,44 @@ exports.dialog = {
]
}
}],
'es_MX': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Bienvenido al constructor de niveles!',
'',
'Estos son los pasos principales:',
'',
' * Preparar el entorno inicial usando comandos de Git',
' * Definir el árbol inicial con ```define start```',
' * Introducir la serie de comandos de git que representan la solución óptima',
' * Crear el árbol objetivo con ```define goal```. El objetivo también determina la solución',
' * Opcionalmente, crea pistas con ```define hint```',
' * Dale un nombre con ```define name```',
' * Opcionalmente, crea un mensaje inicial con ```edit dialog```',
' * ¡Introduce el comando ```finish``` para obtener tu nivel en formato JSON!'
]
}
}],
'es_ES': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Bienvenido al constructor de niveles!',
'',
'Estos son los pasos principales:',
'',
' * Prepara el entorno inicial usando comandos de Git',
' * Define el árbol inicial con ```define start```',
' * Introduce la serie de comandos de git que representan la solución óptima',
' * Crea el árbol objetivo con ```define goal```. El objetivo también determina la solución',
' * Opcionalmente, crea pistas con ```define hint```',
' * Dale un nombre con ```define name```',
' * Opcionalmente, crea un mensaje inicial con ```edit dialog```',
' * ¡Introduce el comando ```finish``` para obtener tu nivel en formato JSON!'
]
}
}],
'pt_BR': [{
type: 'ModalAlert',
options: {
@ -113,6 +151,25 @@ exports.dialog = {
]
}
}],
'gl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Benvido ó constructor de niveis!',
'',
'Estes son os pasos principais:',
'',
' * Prepara o eido inicial usando comandos de Git',
' * Define a árbore inicial con ```define start```',
' * Inserta a secuencia de comandos de git que representan a mellor solución',
' * Define a árbore obxectivo con ```define goal```. O obxectivo tamén determina a solución',
' * Opcionalmente, define axudas con ```define hint```',
' * Dalle un nome con ```define name```',
' * Opcionalmente, define unha mensaxe inicial con ```edit dialog```',
' * Escribe o comando ```finish``` para obter seu nivel en formato JSON!'
]
}
}],
'fr_FR': [{
type: 'ModalAlert',
options: {
@ -210,4 +267,80 @@ exports.dialog = {
]
}
}],
'vi': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Chào mừng đến trình tạo cấp độ!',
'',
'Có những bước chính sau:',
'',
' * Khởi tạo môi trường với các lệnh git',
' * Định nghĩa cây để bắt đầu với ```define start```',
' * Nhập chuỗi lệnh git để tạo đáp án (tốt nhất) của bạn',
' * Định nghĩa cây mục tiêu với ```define goal```. Định nghĩa mục tiêu đồng thời cũng xác định đáp án',
' * Có thể định nghĩa gợi ý với ```define hint```',
' * Chỉnh sửa tên với ```define name```',
' * Có thể định nghĩa hội thoại bắt đầu với ```edit dialog```',
' * Nhập lệnh ```finish``` xuất cấp độ của bạn dưới dạng JSON!'
]
}
}],
'sl_SI': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Dobrodošel v graditelju stopenj!',
'',
'Tu so glavni koraki:',
'',
' * Postavi začetno stanje z git ukazi',
' * Določi začetno drevo z ```define start```',
' * Vnesi zaporedje ukazov, ki predstavljajo (najboljšo) rešitev',
' * Določi ciljno drevo z ```define goal```. Določanje cilja določi tudi rešitev',
' * Opcijsko določi namig z ```define hint```',
' * Uredi ime z ```define name```',
' * Opcijsko določi ličen začetni dialog z ```edit dialog```',
' * Vnesi ukaz ```finish``` za ustvarjanje JSON različice tvoje stopnje!'
]
}
}],
'pl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Witamy w kreatorze poziomów!',
'',
'Oto główne kroki:',
'',
' * Przygotuj środowisko początkowe za pomocą poleceń GIT-a',
' * Zdefiniuj drzewo początkowe za pomocą ```define start```',
' * Wprowadź serię poleceń GIT-a, które tworzą (optymalne) rozwiązanie',
' * Utwórz drzewo celów za pomocą ```define goal```. Określenie celu określa również rozwiązanie',
' * Opcjonalnie utwórz podpowiedzi (wskazówkę) za pomocą ```define hint```',
' * Nadaj nazwę za pomocą ```define name```',
' * Opcjonalnie, utwórz wiadomość początkową za pomocą ```edit dialog```',
' * Wpisz polecenie ```finish```, aby wyświetlić swój poziom w JSON!'
]
}
}],
'ta_IN': [{
type: 'ModalAlert',
options: {
markdowns: [
'## நிலைகளை நிருவகிக்கும் கட்டமைப்பிற்க்கு வருக!',
'',
'அடிப்படை நடைமுறைகள்:',
'',
' * முதலாவதாக ஆரம்ப சூழலை git கட்டளைகள் கொன்டுகொன்டு அமைக்கவும்.',
' * ```define start``` தொடக்க செயல் முறையை வரையறுக்கவும்.',
' * உகந்த தீர்வினை அடையும் git கட்டளைகளின் தொடரை உள்ளிடவும்.',
' * ```define goal``` கொண்டு இலக்கினை அடையும் கிழை வரைமுரைகளை தீர்வுடன் அமைக்கவும்.',
' * தேவை எனில் ```define hint``` கொண்டு உதவி குறிப்பை வரையறுக்கவும்.',
' * ```define name``` கொண்டு பெயரைத் திருத்தவும்.',
' * தேவை எனில் ```edit dialog``` கொண்டு ஒரு நல்ல முன்னுறையை வரையறுக்கவும்.',
' * ```finish``` கொண்டு இந்த நிலையின் JSON!-ஐ அச்சிடுக.'
]
}
}]
};

View file

@ -67,6 +67,28 @@ exports.dialog = {
]
}
}],
'es_MX': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Buen trabajo!',
'',
'Resolviste el nivel en *{numCommands}* comandos; ',
'nuestra mejor solución usa: {best}.'
]
}
}],
'es_ES': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Buen trabajo!',
'',
'Resolviste el nivel en *{numCommands}* comandos; ',
'nuestra mejor solución usa {best}.'
]
}
}],
'pt_BR': [{
type: 'ModalAlert',
options: {
@ -78,6 +100,17 @@ exports.dialog = {
]
}
}],
'gl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Bo traballo!!',
'',
'Resolviches o nivel empregando *{numCommands}* comandos; ',
'a nosa mellor solución é en {best}.'
]
}
}],
'fr_FR': [{
type: 'ModalAlert',
options: {
@ -117,9 +150,53 @@ exports.dialog = {
markdowns: [
'## 훌륭합니다!!',
'',
'*{numCommands}*개의 명렁으로 레벨을 통과했습니다.; ',
'*{numCommands}*개의 명령으로 레벨을 통과했습니다; ',
'모범 답안은 {best}개를 사용합니다.'
]
}
}],
'vi': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Làm tốt lắm!!',
'',
'Bạn hoàn thành cấp độ này với *{numCommands}* câu lệnh; ',
'Đáp án của chúng tôi sử dụng {best}.'
]
}
}],
'sl_SI': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Dobro opravljeno!!',
'',
'Rešil si stopnjo z *{numCommands}* ukazi; ',
'naša rešitev uporabi {best}.'
]
}
}],
'pl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Dobra robota!!',
'',
'Rozwiązałeś poziom używając *{numCommands}* poleceń/ia; ',
'nasze rozwiązanie składa się z {best}.'
]
}
}],
'ta_IN': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ஆக சிரந்த செயல்!!',
'',
'நீங்கள் *{numCommands}* நிலைக்கான கட்டளை(கள்) கொண்டு தீர்வை அடிந்து விட்டீர்கள்; ',
'நமது தீர்வு {best}-ஐ பயன்படுத்து கின்றது.'
]
}
}],
};

View file

@ -18,7 +18,14 @@ exports.dialog = {
'',
'PS: Want to go straight to a sandbox next time?',
'Try out ',
'[this special link](https://pcottle.github.io/learnGitBranching/?NODEMO)'
'[this special link](https://pcottle.github.io/learnGitBranching/?NODEMO)',
'',
'PPS: GitHub (and the industry at large) is moving to naming the default branch as `main` instead of `master` ',
'with [more details available here](https://github.com/github/renaming). In order to accommodate this change in ',
'a backwards-compatible way, these two names will be considered aliases of each other, with `main` being ',
'the preferred one to display. We\'ve made a best-effort attempt to update all of the level content, but ',
'there will be a long-tail of areas we have missed. Please submit a PR (or open an issue) if you spot any ',
'egregious ones, and thanks for helping move away from biased terminology.'
]
}
}],
@ -28,7 +35,7 @@ exports.dialog = {
markdowns: [
'## ¡Bienvenid@ a Learn Git Branching!',
'',
'Esta aplicación está diseñada para ayudar a los principantes ',
'Esta aplicación está diseñada para ayudar a los principiantes ',
'a manejar los poderosos conceptos que hay detrás del trabajo ',
'con ramas (branches) en Git. Esperamos que disfrutes la aplicación ',
'y tal vez incluso ¡que aprendas algo! ',
@ -78,6 +85,118 @@ exports.dialog = {
]
}
}],
'es_MX': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Bienvenid@ a Learn Git Branching!',
'',
'Esta aplicación está diseñada para ayudar a los principiantes',
'a manejar los poderosos conceptos que hay detrás del trabajo',
'con ramas (branches) en Git. Esperamos que disfrutes la aplicación',
'y tal vez incluso ¡que aprendas algo!',
'',
'# ¡Demo!',
'',
'Si no viste la demo, mirala en ésta dirección:',
'',
'[https://pcottle.github.io/learnGitBranching/?demo](https://pcottle.github.io/learnGitBranching/?demo)',
'',
'¿Harto de este mensaje? Agregale `?NODEMO` a la URL para dejar de verlo, como en éste link:',
'',
'[https://pcottle.github.io/learnGitBranching/?NODEMO](?NODEMO)'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## Comandos de git',
'',
'Tienes una gran variedad de comandos de git en este sandbox. He aquí una lista de los incluidos:',
'',
' * commit',
' * branch',
' * checkout',
' * cherry-pick',
' * reset',
' * revert',
' * rebase',
' * merge'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Comparte!',
'',
'Comparte tus árboles con tus amigos usando `export tree` e `import tree`',
'',
'¿Tienes una buena lección que compartir? Prueba construyendo un nivel con `build level` o prueba el nivel de un amigo con `import level`',
'',
'Para ver todos los comandos disponibles, prueba `show commands`. Hay algunos muy prácticos como `undo` y `reset`',
'',
'Por ahora, arranquemos con los `levels`...'
]
}
}],
'es_ES': [{
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Bienvenid@ a Learn Git Branching!',
'',
'Esta aplicación está diseñada para ayudar a los principiantes ',
'a manejar los poderosos conceptos que hay detrás del trabajo ',
'con ramas (branches) en Git. Esperamos que disfrutes la aplicación ',
'y tal vez incluso ¡que aprendas algo! ',
'',
'# ¡Demo!',
'',
'Si no viste la demo, mírala en esta dirección:',
'',
'[https://pcottle.github.io/learnGitBranching/?demo](https://pcottle.github.io/learnGitBranching/?demo)',
'',
'¿Harto de este mensaje? Agrégale `?NODEMO` a la URL para dejar de verlo, como en este link:',
'',
'[https://pcottle.github.io/learnGitBranching/?NODEMO](?NODEMO)'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## Comandos de Git',
'',
'Tienes una gran variedad de comandos de git en este sandbox. Estos incluyen: ',
'',
' * commit',
' * branch',
' * checkout',
' * cherry-pick',
' * reset',
' * revert',
' * rebase',
' * merge'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## ¡Comparte!',
'',
'Comparte tus árboles con tus amigos usando `export tree` e `import tree`',
'',
'¿Tienes una buena lección que compartir? Prueba construyendo un nivel con `build level` o prueba el nivel de un amigo con `import level`',
'',
'Para ver todos los comandos disponibles, escribe `show commands`. Hay algunas joyitas como `undo` y `reset`',
'',
'Por ahora, empecemos con los `levels`...'
]
}
}],
'pt_BR': [{
type: 'ModalAlert',
options: {
@ -134,6 +253,62 @@ exports.dialog = {
]
}
}],
'gl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Benvido a Learn Git Branching!',
'',
'Esta aplicación foi desenvolvida para axudar os iniciados en git a ',
'aprender os poderosos conceptos que hai por detrás do branching con ',
' git. Agardamos que disfrutes desta aplicación, e tal vez, ',
'ata aprendas algunha cousa!',
'',
'# Demostracións!',
'',
'Se aínda non viches a demo, olla aquí:',
'',
'[https://pcottle.github.io/learnGitBranching/?demo](https://pcottle.github.io/learnGitBranching/?demo)',
'',
'¿Farto destas mensaxes? Engade `?NODEMO` á dirección para librarte dela, como no link de abaixo:',
'',
'[https://pcottle.github.io/learnGitBranching/?NODEMO](?NODEMO)'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## Comandos de git',
'',
'Tes a túa disposición unha caixa de área con unha variedade de comandos de git:',
'',
' * commit',
' * branch',
' * checkout',
' * cherry-pick',
' * reset',
' * revert',
' * rebase',
' * merge'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## Compartir e importar!',
'',
'Comparte árbores cos seus amigas con `export tree` e `import tree`',
'',
'¿Tes un enlace moi grande para compartir? Intenta construír un nivel con `build level` ou importe o nivel dun amigo con `import level`',
'',
'Para ver tódolos comandos, usa `show commands`. Hai algunha xoia como `undo` e `reset`',
'',
'Por agora, imos comezar cos `levels`...'
]
}
}],
'de_DE': [{
type: 'ModalAlert',
options: {
@ -396,7 +571,7 @@ exports.dialog = {
markdowns: [
'## Commandes Git',
'',
'Il existe une large variété de commandes git disponibles dans le mode bac à sable. Sont inclues :',
'Il existe une large variété de commandes git disponibles dans le mode bac à sable. Sont incluses :',
'',
' * commit',
' * branch',
@ -501,5 +676,141 @@ exports.dialog = {
'[це спеціальне посилання.](https://pcottle.github.io/learnGitBranching/?NODEMO)'
]
}
}]
}],
'vi': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Chào mừng đến với Học Nhánh Git',
'',
'Bạn có hứng thú học Git? Bạn đến đúng nơi rồi đấy! ',
'"Học Nhánh Git" là cách trực quan và hiệu quả nhất để học Git trên web; ',
'thông qua một loạt các thử thách cấp độ thú vị, bạn sẽ từng bước tìm hiểu sức mạnh của git',
'',
'Sau khi hội thoại này đóng lại, bạn sẽ thấy nhiều cấp độ mà chúng tôi cung cấp. ',
'Nếu bạn là người mới thì hãy bắt đầu từ bài đầu tiên. Nếu bạn đã có hiểu biết cơ bản về git, ',
'hãy thử những bài mang tính thách thức hơn phía sau.',
'',
'Bạn có thể dùng lệnh `show commands` để xem tất cả các lệnh hiện hữu.',
'',
'Ghi chú: Nếu muốn trực tiếp vào hộp cát ở lần sau?',
'Hãy dùng',
'[đường link đặc biệt này của chúng tôi](https://pcottle.github.io/learnGitBranching/?NODEMO)'
]
}
}],
'sl_SI': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Dobrodošel na učenju Git Branchanja',
'',
'Bi se rad naučil Git? No, prišel si na pravo mesto! ',
'"Learn Git Branching" je najbolj vizualen in interaktiven način učenja Git-a ',
'na spletu; zagrizel boš v zanimive stopnje, po korakih boš spoznaval osupljive ',
'funkcije in kaj pa veš, morda ti bo celo zabavno. ;)',
'',
'Za tem oknom boš videl kopico stopenj, ki so na razpolago. Če si ',
'začetnik, kar pogumno, začni s prvo. Če pa že poznaš Git osnove, ',
'se preizkusi v zahtevnejših stopnjah.',
'',
'Vidiš lahko vse ukaze, ki so na voljo, z ukazom `show commands` v terminalu.',
'',
'PS: Bi šel rad naslednjič naravnost v peskovnik?',
'Poizkusi s',
'[to posebno povezavo](https://pcottle.github.io/learnGitBranching/?NODEMO)'
]
}
}],
'pl': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Witaj w Learn Git Branching!',
'',
'Celem tej aplikacji jest zilustrowanie rozległych i złożonych relacji pomiędzy procesami związanymi z pracą z GIT-em.',
'Mam nadzieję, że ci się to spodoba i może nawet się czegoś nauczysz!',
'"Learn Git Branching" to najbardziej wizualny i interaktywny sposób na naukę GIT-a w sieci.',
'Będziesz miał do czynienia z ekscytującymi poziomami wraz z pokazaniem krok po kroku potężnych funkcji, a może nawet z odrobiną zabawy po drodze.',
'',
'Jeśli jesteś początkujący, po prostu zacznij od pierwszego poziomu.',
'Jeśli znasz już podstawy GIT-a, wypróbuj niektóre z naszych późniejszych, bardziej wymagających poziomów.',
'',
'# Demo!',
'',
'Jeśli nie widziałeś tej demonstracji, możesz ją obejrzeć tutaj:',
'',
'[https://pcottle.github.io/learnGitBranching/?demo](https://pcottle.github.io/learnGitBranching/?demo)',
'',
'Masz dość tego okna? Dodaj `?NODEMO` do adresu URL, aby się go pozbyć, w ten sposób:',
'',
'[https://pcottle.github.io/learnGitBranching/?NODEMO](?NODEMO)'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## Komendy GIT-a',
'',
'W trybie piaskownicy dostępna jest duża liczba poleceń GIT. Między innymi',
'',
' * commit',
' * branch',
' * checkout',
' * cherry-pick',
' * reset',
' * revert',
' * rebase',
' * merge'
]
}
}, {
type: 'ModalAlert',
options: {
markdowns: [
'## Dzielenie się jest Fajne!',
'',
'Podziel się tymi drzewami GIT-a z przyjaciółmi, wpisując `export tree` oraz `import tree`.',
'',
'Czy masz coś, co warto wiedzieć o GIT-cie? Spróbuj zbudować swój poziom wpisując `build level` lub spróbuj poziomu znajomego wpisując `import level`',
'',
'Aby zobaczyć wszystkie polecenia, wpisz `show commands`. Pod spodem są "małe skarby" jak `undo`(cofnij) i `reset`',
'',
'Na razie zacznijmy od wpisania `levels`...'
]
}
}],
'ta_IN': [{
type: 'ModalAlert',
options: {
markdowns: [
'## Git Branching கற்க வரவேற்கிறோம்',
'',
'கிட் கற்க ஆர்வமா? அப்படியானால் நீங்கள் சரியான இடத்திற்கு வந்துவிட்டீர்கள்! ',
'"Learn Git Branching" Git ஐக் கற்றுக்கொள்வதற்கான வரைபடம் மற்றும் செயல்முறை ',
'பயிற்சியுடன் கூடிய சிரந்த கருவி; ',
'உங்களை சோதிக்கும் வகையிலான நிலைகளுடன் மிகுந்த சக்திவாய்ந்த அம்சங்களை ',
'படிப்படியாகவும், சில சமையம் விளையாட்டாகவும் கற்றுத்தர கூடியது.',
'',
'இந்த அறிவிற்ப்புக்கு பிறகு, நாங்கள் வழங்க உள்ள பல்வேறு நிலைகளை நீங்கள் காண்பீர்கள். ',
'நீங்கள் ஆரம்ம நிலையில் இருந்தால், முதல் கட்டத்தில் இருந்து தொடங்கவும். ',
'கிட்டின் சில அடிப்படைகளை நீங்கள் ஏற்கனவே அறிந்திருந்தால், மெலும் உள்ள கடினமான கட்டங்களை முயற்ச்சி செய்யுங்கள்.',
'',
'தேவையானால் `show commands` ஐ பயன்படுத்தி அனைத்து கட்டளைகளையும் முனையத்தில் பார்க்கலாம்.',
'',
'பின்குறிப்பு: அடுத்தமுறை நேராக sandbox செல்ல வேண்டுமா?',
'அப்படியானால் பின் வரும் இணைப்பை பயன்பாடித்துக ',
'[this special link](https://pcottle.github.io/learnGitBranching/?NODEMO)',
'',
'பின்குறிப்பு: GitHub (பெரிய அளவில் பயன்பாட்டில் உள்ள இணையதலம்) `main` என்ற கிழையை `master`-க்கு பதில் ',
'முன்னிருப்பு கிழையாக பயன் படுத்த உள்ளது [more details available here](https://github.com/github/renaming). ',
'இந்த மாற்றத்தை பின்னோக்கி இணக்கமான வழியில் பொருத்துவதற்காக, `main`-ஐ முதன்மையாக கருதி ',
'இந்த இரண்டு பெயர்களும் ஒன்றுக்கொன்று மாற்றுப்பெயர்களாகக் கருதப்படும். ',
'இந்த மாற்றத்தை அனைத்து நிலை உள்ளடக்கங்களிலும் புதுப்பிக்க நாங்கள் சிறந்த முயற்சியை ',
'மேற்கொண்டோம், ஆயினும் ஏதேனும் விடுபட்டி இருந்தால் PR உருவாக்கி உதவுங்கள்.',
'ஒருபக்கச்சார்பான சொற்களிலிருந்து விலகிச் செல்ல உதவியதற்கு நன்றி.'
]
}
}],
};

View file

@ -1,4 +1,4 @@
var _ = require('underscore');
var escapeString = require('../util/escapeString');
var intl = require('../intl');
var Graph = require('../graph');
@ -19,7 +19,7 @@ function isColonRefspec(str) {
}
var assertIsRef = function(engine, ref) {
engine.resolveID(ref); // will throw giterror if cant resolve
engine.resolveID(ref); // will throw git error if can't resolve
};
var validateBranchName = function(engine, name) {
@ -83,7 +83,7 @@ var assertOriginSpecified = function(generalArgs) {
if (generalArgs[0] !== 'origin') {
throw new GitError({
msg: intl.todo(
generalArgs[0] + ' is not a remote in your repository! try adding origin that argument'
generalArgs[0] + ' is not a remote in your repository! try adding origin to that argument'
)
});
}
@ -107,7 +107,7 @@ var assertBranchIsRemoteTracking = function(engine, branchName) {
if (!tracking) {
throw new GitError({
msg: intl.todo(
branchName + ' is not a remote tracking branch! I dont know where to push'
branchName + ' is not a remote tracking branch! I don\'t know where to push'
)
});
}
@ -190,7 +190,7 @@ var commandConfig = {
var set = Graph.getUpstreamSet(engine, 'HEAD');
// first resolve all the refs (as an error check)
var toCherrypick = _.map(generalArgs, function(arg) {
var toCherrypick = generalArgs.map(function (arg) {
var commit = engine.getCommitFromRef(arg);
// and check that its not upstream
if (set[commit.get('id')]) {
@ -253,9 +253,9 @@ var commandConfig = {
source = firstArg;
assertIsBranch(engine.origin, source);
// get o/master locally if master is specified
destination = engine.origin.refs[source].getPrefixedID();
destination = engine.origin.resolveID(source).getPrefixedID();
} else {
// cant be detached
// can't be detached
if (engine.getDetachedHead()) {
throw new GitError({
msg: intl.todo('Git pull can not be executed in detached HEAD mode if no remote branch specified!')
@ -394,7 +394,7 @@ var commandConfig = {
source = firstArg;
assertIsBranch(engine.origin, source);
// get o/master locally if master is specified
destination = engine.origin.refs[source].getPrefixedID();
destination = engine.origin.resolveID(source).getPrefixedID();
}
if (source) { // empty string fails this check
assertIsRef(engine.origin, source);
@ -431,7 +431,7 @@ var commandConfig = {
names = names.concat(generalArgs);
command.validateArgBounds(names, 1, Number.MAX_VALUE, '-d');
_.each(names, function(name) {
names.forEach(function(name) {
engine.validateAndDeleteBranch(name);
});
return;
@ -447,8 +447,8 @@ var commandConfig = {
assertIsRemoteBranch(engine, remoteBranch);
assertIsBranch(engine, branch);
engine.setLocalToTrackRemote(
engine.refs[branch],
engine.refs[remoteBranch]
engine.resolveID(branch),
engine.resolveID(remoteBranch)
);
return;
}
@ -519,7 +519,7 @@ var commandConfig = {
command.addWarning(
intl.str('git-warning-hard')
);
// dont absorb the arg off of --hard
// don't absorb the arg off of --hard
generalArgs = generalArgs.concat(commandOptions['--hard']);
}
@ -574,25 +574,26 @@ var commandConfig = {
}
},
revlist: {
dontCountForGolf: true,
displayName: 'rev-list',
regex: /^git +rev-list($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
command.validateArgBounds(generalArgs, 1);
engine.revlist(generalArgs);
}
},
log: {
dontCountForGolf: true,
regex: /^git +log($|\s)/,
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
if (generalArgs.length == 2) {
// do fancy git log branchA ^branchB
if (generalArgs[1][0] == '^') {
engine.logWithout(generalArgs[0], generalArgs[1]);
} else {
throw new GitError({
msg: intl.str('git-error-options')
});
}
}
command.oneArgImpliedHead(generalArgs);
engine.log(generalArgs[0]);
command.impliedHead(generalArgs, 0);
engine.log(generalArgs);
}
},
@ -742,7 +743,7 @@ var commandConfig = {
var refspecParts = firstArg.split(':');
source = refspecParts[0];
destination = validateBranchName(engine, refspecParts[1]);
if (source === "" && !engine.origin.refs[destination]) {
if (source === "" && !engine.origin.resolveID(destination)) {
throw new GitError({
msg: intl.todo(
'cannot delete branch ' + options.destination + ' which doesnt exist'
@ -769,7 +770,7 @@ var commandConfig = {
sourceObj.getRemoteTrackingBranchID()) {
assertBranchIsRemoteTracking(engine, source);
var remoteBranch = sourceObj.getRemoteTrackingBranchID();
destination = engine.refs[remoteBranch].getBaseID();
destination = engine.resolveID(remoteBranch).getBaseID();
} else {
destination = validateBranchName(engine, source);
}
@ -810,8 +811,41 @@ var commandConfig = {
tag: {
regex: /^git +tag($|\s)/,
options: [
'-d'
],
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
var commandOptions = command.getOptionsMap();
if (commandOptions['-d']) {
var tagID = commandOptions['-d'];
var tagToRemove;
assertIsRef(engine, tagID);
command.oneArgImpliedHead(tagID);
engine.tagCollection.each(function(tag) {
if(tag.get('id') == tagID){
tagToRemove = tag;
}
}, true);
if(tagToRemove == undefined){
throw new GitError({
msg: intl.todo(
'No tag found, nothing to remove'
)
});
}
engine.tagCollection.remove(tagToRemove);
delete engine.refs[tagID];
engine.gitVisuals.refreshTree();
return;
}
if (generalArgs.length === 0) {
var tags = engine.getTags();
engine.printTags(tags);
@ -821,6 +855,48 @@ var commandConfig = {
command.twoArgsImpliedHead(generalArgs);
engine.tag(generalArgs[0], generalArgs[1]);
}
},
switch: {
sc: /^(gsw|git sw)($|\s)/,
regex: /^git +switch($|\s)/,
options: [
'-c',
'-'
],
execute: function(engine, command) {
var generalArgs = command.getGeneralArgs();
var commandOptions = command.getOptionsMap();
var args = null;
if (commandOptions['-c']) {
// the user is really trying to just make a
// branch and then switch to it. so first:
args = commandOptions['-c'].concat(generalArgs);
command.twoArgsImpliedHead(args, '-c');
var validId = engine.validateBranchName(args[0]);
engine.branch(validId, args[1]);
engine.checkout(validId);
return;
}
if (commandOptions['-']) {
// get the heads last location
var lastPlace = engine.HEAD.get('lastLastTarget');
if (!lastPlace) {
throw new GitError({
msg: intl.str('git-result-nothing')
});
}
engine.HEAD.set('target', lastPlace);
return;
}
command.validateArgBounds(generalArgs, 1, 1);
engine.checkout(engine.crappyUnescape(generalArgs[0]));
}
}
};
@ -830,7 +906,7 @@ var instantCommands = [
intl.str('git-version'),
'<br/>',
intl.str('git-usage'),
_.escape(intl.str('git-usage-command')),
escapeString(intl.str('git-usage-command')),
'<br/>',
intl.str('git-supported-commands'),
'<br/>'
@ -838,9 +914,10 @@ var instantCommands = [
var commands = require('../commands').commands.getOptionMap()['git'];
// build up a nice display of what we support
_.each(commands, function(commandOptions, command) {
Object.keys(commands).forEach(function(command) {
var commandOptions = commands[command];
lines.push('git ' + command);
_.each(commandOptions, function(vals, optionName) {
Object.keys(commandOptions).forEach(function(optionName) {
lines.push('\t ' + optionName);
}, this);
}, this);
@ -856,4 +933,3 @@ var instantCommands = [
exports.commandConfig = commandConfig;
exports.instantCommands = instantCommands;

View file

@ -36,7 +36,7 @@ function getMockFactory() {
};
mockFactory.highlightEachWithPromise = function(chain, toRebase, destBranch) {
// dont add any steps
// don't add any steps
return chain;
};
@ -109,6 +109,8 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
var chain = deferred.promise;
var startTime = new Date().getTime();
var commands = [];
util.splitTextCommand(value, function(commandStr) {
chain = chain.then(function() {
var commandObj = new Command({
@ -117,6 +119,7 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
var thisDeferred = Q.defer();
this.gitEngine.dispatch(commandObj, thisDeferred);
commands.push(commandObj);
return thisDeferred.promise;
}.bind(this));
}, this);
@ -124,7 +127,7 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
chain.then(function() {
var nowTime = new Date().getTime();
if (entireCommandPromise) {
entireCommandPromise.resolve();
entireCommandPromise.resolve(commands);
}
});
@ -135,8 +138,8 @@ HeadlessGit.prototype.sendCommand = function(value, entireCommandPromise) {
console.log('!!!!!!!!!!!!!!!!!!!!!!');
});
deferred.resolve();
return chain;
};
exports.HeadlessGit = HeadlessGit;
exports.getTreeQuick = getTreeQuick;

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,3 @@
var _ = require('underscore');
function invariant(truthy, reason) {
if (!truthy) {
throw new Error(reason);
@ -44,7 +42,7 @@ var Graph = {
if (type == 'HEAD') {
var headJSON = tree.HEAD;
var HEAD = new Ref(_.extend(
var HEAD = new Ref(Object.assign(
tree.HEAD,
{
target: this.getOrMakeRecursive(tree, createdSoFar, headJSON.target)
@ -57,7 +55,7 @@ var Graph = {
if (type == 'branch') {
var branchJSON = tree.branches[objID];
var branch = new Branch(_.extend(
var branch = new Branch(Object.assign(
tree.branches[objID],
{
target: this.getOrMakeRecursive(tree, createdSoFar, branchJSON.target)
@ -70,7 +68,7 @@ var Graph = {
if (type == 'tag') {
var tagJSON = tree.tags[objID];
var tag = new Tag(_.extend(
var tag = new Tag(Object.assign(
tree.tags[objID],
{
target: this.getOrMakeRecursive(tree, createdSoFar, tagJSON.target)
@ -85,11 +83,11 @@ var Graph = {
var commitJSON = tree.commits[objID];
var parentObjs = [];
_.each(commitJSON.parents, function(parentID) {
commitJSON.parents.forEach(function(parentID) {
parentObjs.push(this.getOrMakeRecursive(tree, createdSoFar, parentID));
}, this);
var commit = new Commit(_.extend(
var commit = new Commit(Object.assign(
commitJSON,
{
parents: parentObjs,
@ -143,7 +141,7 @@ var Graph = {
var here = queue.pop();
var rents = here.get('parents');
_.each(rents, addToExplored);
(rents || []).forEach(addToExplored);
}
return exploredSet;
},
@ -151,7 +149,7 @@ var Graph = {
getUniqueObjects: function(objects) {
var unique = {};
var result = [];
_.forEach(objects, function(object) {
objects.forEach(function(object) {
if (unique[object.id]) {
return;
}

View file

@ -54,6 +54,10 @@ TreeCompare.dispatchShallow = function(levelBlob, goalTreeString, treeToCompare)
return TreeCompare.compareBranchWithinTrees(
treeToCompare, goalTreeString, 'master'
);
case !!levelBlob.compareAllBranchesAndEnforceBranchCleanup:
return TreeCompare.compareAllBranchesAndEnforceBranchCleanup(
treeToCompare, goalTreeString
);
case !!levelBlob.compareOnlyBranches:
return TreeCompare.compareAllBranchesWithinTrees(
treeToCompare, goalTreeString
@ -78,85 +82,103 @@ TreeCompare.dispatchShallow = function(levelBlob, goalTreeString, treeToCompare)
};
// would love to have copy properties here.. :(
TreeCompare.compareAllBranchesWithinTreesAndHEAD = function(treeA, treeB) {
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
TreeCompare.compareAllBranchesWithinTreesAndHEAD = function(treeToCompare, goalTree) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
// also compare tags!! for just one level
return treeA.HEAD.target === treeB.HEAD.target &&
this.compareAllBranchesWithinTrees(treeA, treeB) &&
this.compareAllTagsWithinTrees(treeA, treeB);
return treeToCompare.HEAD.target === goalTree.HEAD.target &&
this.compareAllBranchesWithinTrees(treeToCompare, goalTree) &&
this.compareAllTagsWithinTrees(treeToCompare, goalTree);
};
TreeCompare.compareAllBranchesWithinTrees = function(treeA, treeB) {
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
TreeCompare.compareAllBranchesAndEnforceBranchCleanup = function(treeToCompare, goalTree) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
var allBranches = _.extend(
// Unlike compareAllBranchesWithinTrees, here we consider both the branches
// in the goalTree and the branches in the treeToCompare. This means that
// we enfoce that you clean up any branches that you have locally that
// the goal does not have. this is helpful when we want to verify that you
// have deleted branch, for instance.
var allBranches = Object.assign(
{},
treeA.branches,
treeB.branches
treeToCompare.branches,
goalTree.branches
);
var result = true;
_.uniq(allBranches, function(info, branch) {
result = result && this.compareBranchWithinTrees(treeA, treeB, branch);
}, this);
return result;
return Object.keys(allBranches).every(function(branch) {
return this.compareBranchWithinTrees(treeToCompare, goalTree, branch);
}.bind(this));
};
TreeCompare.compareAllTagsWithinTrees = function(treeA, treeB) {
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
this.reduceTreeFields([treeA, treeB]);
return _.isEqual(treeA.tags, treeB.tags);
TreeCompare.compareAllBranchesWithinTrees = function(treeToCompare, goalTree) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
/**
* Disclaimer / reminder!! We only care about branches in the goal tree;
* if you have extra branches in your source tree thats ok. but that means
* the arguments here are important -- always call this function with
* goalTree being the latter argument, since we will discard extra branches
* from treeToCompare (the first argument).
*/
return Object.keys(goalTree.branches).every(function(branch) {
return this.compareBranchWithinTrees(treeToCompare, goalTree, branch);
}.bind(this));
};
TreeCompare.compareBranchesWithinTrees = function(treeA, treeB, branches) {
TreeCompare.compareAllTagsWithinTrees = function(treeToCompare, goalTree) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
this.reduceTreeFields([treeToCompare, goalTree]);
return _.isEqual(treeToCompare.tags, goalTree.tags);
};
TreeCompare.compareBranchesWithinTrees = function(treeToCompare, goalTree, branches) {
var result = true;
_.each(branches, function(branchName) {
result = result && this.compareBranchWithinTrees(treeA, treeB, branchName);
branches.forEach(function(branchName) {
result = result && this.compareBranchWithinTrees(treeToCompare, goalTree, branchName);
}, this);
return result;
};
TreeCompare.compareBranchWithinTrees = function(treeA, treeB, branchName) {
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
this.reduceTreeFields([treeA, treeB]);
TreeCompare.compareBranchWithinTrees = function(treeToCompare, goalTree, branchName) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
this.reduceTreeFields([treeToCompare, goalTree]);
var recurseCompare = this.getRecurseCompare(treeA, treeB);
var branchA = treeA.branches[branchName];
var branchB = treeB.branches[branchName];
var recurseCompare = this.getRecurseCompare(treeToCompare, goalTree);
var branchA = treeToCompare.branches[branchName];
var branchB = goalTree.branches[branchName];
return _.isEqual(branchA, branchB) &&
recurseCompare(treeA.commits[branchA.target], treeB.commits[branchB.target]);
recurseCompare(treeToCompare.commits[branchA.target], goalTree.commits[branchB.target]);
};
TreeCompare.compareAllBranchesWithinTreesHashAgnostic = function(treeA, treeB) {
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
this.reduceTreeFields([treeA, treeB]);
TreeCompare.compareAllBranchesWithinTreesHashAgnostic = function(treeToCompare, goalTree) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
this.reduceTreeFields([treeToCompare, goalTree]);
var allBranches = _.extend(
var allBranches = Object.assign(
{},
treeA.branches,
treeB.branches
treeToCompare.branches,
goalTree.branches
);
var branchNames = [];
_.each(allBranches, function(obj, name) { branchNames.push(name); });
var branchNames = Object.keys(allBranches || {});
return this.compareBranchesWithinTreesHashAgnostic(treeA, treeB, branchNames);
return this.compareBranchesWithinTreesHashAgnostic(treeToCompare, goalTree, branchNames);
};
TreeCompare.compareBranchesWithinTreesHashAgnostic = function(treeA, treeB, branches) {
TreeCompare.compareBranchesWithinTreesHashAgnostic = function(treeToCompare, goalTree, branches) {
// we can't DRY unfortunately here because we need a special _.isEqual function
// for both the recursive compare and the branch compare
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
this.reduceTreeFields([treeA, treeB]);
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
this.reduceTreeFields([treeToCompare, goalTree]);
// get a function to compare branch objects without hashes
var compareBranchObjs = function(branchA, branchB) {
@ -164,31 +186,32 @@ TreeCompare.compareBranchesWithinTreesHashAgnostic = function(treeA, treeB, bran
return false;
}
// dont mess up the rest of comparison
branchA = _.clone(branchA);
branchB = _.clone(branchB);
// don't mess up the rest of comparison
branchA = Object.assign({}, branchA);
branchB = Object.assign({}, branchB);
branchA.target = this.getBaseRef(branchA.target);
branchB.target = this.getBaseRef(branchB.target);
return _.isEqual(branchA, branchB);
}.bind(this);
// and a function to compare recursively without worrying about hashes
var recurseCompare = this.getRecurseCompareHashAgnostic(treeA, treeB);
var recurseCompare = this.getRecurseCompareHashAgnostic(treeToCompare, goalTree);
var result = true;
_.each(branches, function(branchName) {
var branchA = treeA.branches[branchName];
var branchB = treeB.branches[branchName];
branches.forEach(function(branchName) {
var branchA = treeToCompare.branches[branchName];
var branchB = goalTree.branches[branchName];
result = result && compareBranchObjs(branchA, branchB) &&
recurseCompare(treeA.commits[branchA.target], treeB.commits[branchB.target]);
recurseCompare(treeToCompare.commits[branchA.target], goalTree.commits[branchB.target]);
}, this);
return result;
};
TreeCompare.evalAsserts = function(tree, assertsPerBranch) {
var result = true;
_.each(assertsPerBranch, function(asserts, branchName) {
Object.keys(assertsPerBranch).forEach(function(branchName) {
var asserts = assertsPerBranch[branchName];
result = result && this.evalAssertsOnBranch(tree, branchName, asserts);
}, this);
return result;
@ -217,7 +240,7 @@ TreeCompare.evalAssertsOnBranch = function(tree, branchName, asserts) {
}
var result = true;
_.each(asserts, function(assert) {
asserts.forEach(function(assert) {
try {
result = result && assert(data);
} catch (err) {
@ -251,7 +274,7 @@ TreeCompare.getNumHashes = function(ref) {
return func(results);
}
}
throw new Error('couldnt parse ref ' + ref);
throw new Error('couldn\'t parse ref ' + ref);
};
TreeCompare.getBaseRef = function(ref) {
@ -263,14 +286,14 @@ TreeCompare.getBaseRef = function(ref) {
return 'C' + bits[1];
};
TreeCompare.getRecurseCompareHashAgnostic = function(treeA, treeB) {
TreeCompare.getRecurseCompareHashAgnostic = function(treeToCompare, goalTree) {
// here we pass in a special comparison function to pass into the base
// recursive compare.
// some buildup functions
var getStrippedCommitCopy = function(commit) {
if (!commit) { return {}; }
return _.extend(
return Object.assign(
{},
commit,
{
@ -286,10 +309,10 @@ TreeCompare.getRecurseCompareHashAgnostic = function(treeA, treeB) {
getStrippedCommitCopy(commitB)
);
};
return this.getRecurseCompare(treeA, treeB, {isEqual: isEqual});
return this.getRecurseCompare(treeToCompare, goalTree, {isEqual: isEqual});
};
TreeCompare.getRecurseCompare = function(treeA, treeB, options) {
TreeCompare.getRecurseCompare = function(treeToCompare, goalTree, options) {
options = options || {};
// we need a recursive comparison function to bubble up the branch
@ -305,17 +328,17 @@ TreeCompare.getRecurseCompare = function(treeA, treeB, options) {
// so the index lookup is valid. for merge commits this will duplicate some of the
// checking (because we aren't doing graph search) but it's not a huge deal
var maxNumParents = Math.max(commitA.parents.length, commitB.parents.length);
_.each(_.range(maxNumParents), function(index) {
for (var index = 0; index < maxNumParents; index++) {
var pAid = commitA.parents[index];
var pBid = commitB.parents[index];
// if treeA or treeB doesn't have this parent,
// if treeToCompare or goalTree doesn't have this parent,
// then we get an undefined child which is fine when we pass into _.isEqual
var childA = treeA.commits[pAid];
var childB = treeB.commits[pBid];
var childA = treeToCompare.commits[pAid];
var childB = goalTree.commits[pBid];
result = result && recurseCompare(childA, childB);
}, this);
}
// if each of our children recursively are equal, we are good
return result;
};
@ -327,9 +350,10 @@ TreeCompare.lowercaseTree = function(tree) {
tree.HEAD.target = tree.HEAD.target.toLocaleLowerCase();
}
var branches = tree.branches;
var branches = tree.branches || {};
tree.branches = {};
_.each(branches, function(obj, name) {
Object.keys(branches).forEach(function(name) {
var obj = branches[name];
obj.id = obj.id.toLocaleLowerCase();
tree.branches[name.toLocaleLowerCase()] = obj;
});
@ -377,8 +401,9 @@ TreeCompare.reduceTreeFields = function(trees) {
tags: {}
};
_.each(trees, function(tree) {
_.each(treeDefaults, function(val, key) {
trees.forEach(function(tree) {
Object.keys(treeDefaults).forEach(function(key) {
var val = treeDefaults[key];
if (tree[key] === undefined) {
tree[key] = val;
}
@ -388,10 +413,11 @@ TreeCompare.reduceTreeFields = function(trees) {
// this function saves only the specified fields of a tree
var saveOnly = function(tree, treeKey, saveFields, sortFields) {
var objects = tree[treeKey];
_.each(objects, function(obj, objKey) {
Object.keys(objects).forEach(function(objKey) {
var obj = objects[objKey];
// our blank slate to copy over
var blank = {};
_.each(saveFields, function(field) {
saveFields.forEach(function(field) {
if (obj[field] !== undefined) {
blank[field] = obj[field];
} else if (defaults[field] !== undefined) {
@ -399,7 +425,7 @@ TreeCompare.reduceTreeFields = function(trees) {
}
});
_.each(sortFields, function(field) {
Object.values(sortFields || {}).forEach(function(field) {
// also sort some fields
if (obj[field]) {
obj[field].sort();
@ -410,7 +436,7 @@ TreeCompare.reduceTreeFields = function(trees) {
});
};
_.each(trees, function(tree) {
trees.forEach(function(tree) {
saveOnly(tree, 'commits', commitSaveFields, commitSortFields);
saveOnly(tree, 'branches', branchSaveFields);
saveOnly(tree, 'tags', tagSaveFields);
@ -425,15 +451,15 @@ TreeCompare.reduceTreeFields = function(trees) {
}, this);
};
TreeCompare.compareTrees = function(treeA, treeB) {
treeA = this.convertTreeSafe(treeA);
treeB = this.convertTreeSafe(treeB);
TreeCompare.compareTrees = function(treeToCompare, goalTree) {
treeToCompare = this.convertTreeSafe(treeToCompare);
goalTree = this.convertTreeSafe(goalTree);
// now we need to strip out the fields we don't care about, aka things
// like createTime, message, author
this.reduceTreeFields([treeA, treeB]);
this.reduceTreeFields([treeToCompare, goalTree]);
return _.isEqual(treeA, treeB);
return _.isEqual(treeToCompare, goalTree);
};
module.exports = TreeCompare;

View file

@ -1,54 +1,33 @@
var sys = require('sys');
var { join } = require('path');
var { readFileSync } = require('fs');
var util = require('../util');
var child_process = require('child_process');
var strings = require('../intl/strings').strings;
var { strings } = require('../intl/strings');
var searchCommand = 'grep -C 2 -r "intl.str(" ../../';
var genBadKeyCommand = function(key) {
return 'grep -r "' + key + '" ../../';
};
var easyRegex = /intl\.str\(\s*'([a-zA-Z\-]+)'/g;
var easyRegex = /intl.str\('([a-zA-Z\-]+)'/g;
var hardRegex = /\s+'([a-z\-]+)',/g;
var allKetSet = new Set(Object.keys(strings));
allKetSet.delete('error-untranslated'); // used in ./index.js
var findKey = function(badKey) {
child_process.exec(genBadKeyCommand(badKey), function(err, output) {
console.log(output);
});
};
var goodKeys = 0;
var goodKeySet = new Set();
var validateKey = function(key) {
if (!strings[key]) {
console.log('NO KEY for: "', key, '"');
findKey(key);
} else {
goodKeys++;
goodKeySet.add(key);
allKetSet.delete(key);
}
};
var processLines = function(lines) {
lines.forEach(function(line) {
var results = easyRegex.exec(line);
if (results && results[1]) {
validateKey(results[1]);
return;
}
// could be a multi-liner
results = hardRegex.exec(line);
if (results && results[1]) {
validateKey(results[1]);
}
});
};
if (!util.isBrowser()) {
child_process.exec(
searchCommand,
function(err, output) {
processLines(output.split('\n'));
console.log(goodKeys + ' good keys found!');
util.readDirDeep(join(__dirname, '../../')).forEach(function(path) {
var content = readFileSync(path);
var match;
while (match = easyRegex.exec(content)) {
validateKey(match[1]);
}
);
});
console.log(goodKeySet.size, ' good keys found!');
console.log(allKetSet.size, ' keys did not use!');
console.log(allKetSet);
}

View file

@ -11,7 +11,7 @@ var fallbackMap = {
// lets change underscores template settings so it interpolates
// things like "{branchName} does not exist".
var templateSettings = _.clone(_.templateSettings);
var templateSettings = Object.assign({}, _.templateSettings);
templateSettings.interpolate = /\{(.+?)\}/g;
var template = exports.template = function(str, params) {
return _.template(str, params, templateSettings);
@ -57,7 +57,7 @@ var str = exports.str = function(key, params) {
var getIntlKey = exports.getIntlKey = function(obj, key, overrideLocale) {
if (!obj || !obj[key]) {
throw new Error('that key ' + key + 'doesnt exist in this blob' + obj);
throw new Error('that key ' + key + 'doesn\'t exist in this blob' + obj);
}
if (!obj[key][getDefaultLocale()]) {
console.warn(
@ -98,7 +98,7 @@ exports.getStartDialog = function(level) {
var startDialog = getIntlKey(level, 'startDialog');
if (startDialog) { return startDialog; }
// this level translation isnt supported yet, so lets add
// this level translation isn't supported yet, so lets add
// an alert to the front and give the english version.
var errorAlert = {
type: 'ModalAlert',
@ -106,7 +106,8 @@ exports.getStartDialog = function(level) {
markdown: str('error-untranslated')
}
};
var startCopy = _.clone(
var startCopy = Object.assign(
{},
level.startDialog[getDefaultLocale()] || level.startDialog
);
startCopy.childViews.unshift(errorAlert);

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var Q = require('q');
@ -55,7 +54,7 @@ var LevelBuilder = Level.extend({
// if we are editing a level our behavior is a bit different
var editLevelJSON;
if (options.editLevel) {
LevelStore.getLevel(options.editLevel);
editLevelJSON = LevelStore.getLevel(options.editLevel);
options.level = editLevelJSON;
}
@ -68,7 +67,7 @@ var LevelBuilder = Level.extend({
this.definedGoal = true;
}
// we wont be using this stuff, and it is deleted to ensure we overwrite all functions that
// we won't be using this stuff, and it is deleted to ensure we overwrite all functions that
// include that functionality
delete this.treeCompare;
delete this.solved;
@ -271,7 +270,7 @@ var LevelBuilder = Level.extend({
this.startDialogObj = levelObj;
}.bind(this))
.fail(function() {
// nothing to do, they dont want to edit it apparently
// nothing to do, they don't want to edit it apparently
})
.done(function() {
if (command) {
@ -335,12 +334,12 @@ var LevelBuilder = Level.extend({
.then(function() {
// oh boy this is complex
var whenEditedDialog = Q.defer();
// the undefined here is the command that doesnt need resolving just yet...
// the undefined here is the command that doesn't need resolving just yet...
this.editDialog(undefined, whenEditedDialog);
return whenEditedDialog.promise;
}.bind(this))
.fail(function() {
// if they dont want to edit the start dialog, do nothing
// if they don't want to edit the start dialog, do nothing
})
.done(function() {
askForStartDeferred.resolve();
@ -360,7 +359,7 @@ var LevelBuilder = Level.extend({
},
getExportObj: function() {
var compiledLevel = _.extend(
var compiledLevel = Object.assign(
{},
this.level
);
@ -385,14 +384,14 @@ var LevelBuilder = Level.extend({
'help builder': LevelBuilder.__super__.startDialog
};
if (!methodMap[command.get('method')]) {
throw new Error('woah we dont support that method yet');
throw new Error('woah we don\'t support that method yet');
}
methodMap[command.get('method')].apply(this, arguments);
},
afterCommandDefer: function(defer, command) {
// we dont need to compare against the goal anymore
// we don't need to compare against the goal anymore
defer.resolve();
},

View file

@ -1,12 +1,12 @@
var _ = require('underscore');
var Q = require('q');
var React = require('react');
var ReactDOM = require('react-dom');
var util = require('../util');
var Main = require('../app');
var intl = require('../intl');
var log = require('../log');
var React = require('react');
var Errors = require('../util/errors');
var Sandbox = require('../sandbox/').Sandbox;
var GlobalStateActions = require('../actions/GlobalStateActions');
@ -69,8 +69,15 @@ var Level = Sandbox.extend({
// if there is a multiview in the beginning, open that
// and let it resolve our deferred
if (GlobalStateStore.getShouldDisableLevelInstructions()) {
setTimeout(function() {
deferred.resolve();
}, 100);
return;
}
if (this.level.startDialog && !this.testOption('noIntroDialog')) {
new MultiView(_.extend(
new MultiView(Object.assign(
{},
intl.getStartDialog(this.level),
{ deferred: deferred }
@ -99,7 +106,7 @@ var Level = Sandbox.extend({
var dialog = $.extend({}, intl.getStartDialog(levelObj));
// grab the last slide only
dialog.childViews = dialog.childViews.slice(-1);
new MultiView(_.extend(
new MultiView(Object.assign(
dialog,
{ deferred: deferred }
));
@ -140,7 +147,7 @@ var Level = Sandbox.extend({
parent: this
}
);
React.render(
ReactDOM.render(
this.levelToolbar,
document.getElementById('levelToolbarMount')
);
@ -166,6 +173,14 @@ var Level = Sandbox.extend({
startOffCommand: function() {
var method = this.options.command.get('method');
if (GlobalStateStore.getShouldDisableLevelInstructions()) {
Main.getEventBaton().trigger(
'commandSubmitted',
'hint; show goal'
);
return;
}
if (!this.testOption('noStartCommand') && method !== 'importLevelNow') {
Main.getEventBaton().trigger(
'commandSubmitted',
@ -401,13 +416,14 @@ var Level = Sandbox.extend({
doesCommandCountTowardsTotal: function(command) {
if (command.get('error')) {
// dont count errors towards our count
// don't count errors towards our count
return false;
}
var matched = false;
_.each(Commands.commands.getCommandsThatCount(), function(map) {
_.each(map, function(regex) {
var commandsThatCount = Commands.commands.getCommandsThatCount();
Object.values(commandsThatCount).forEach(function(map) {
Object.values(map).forEach(function(regex) {
matched = matched || regex.test(command.get('rawStr'));
});
});
@ -497,7 +513,7 @@ var Level = Sandbox.extend({
finishAnimationChain = deferred.promise;
Main.getEventBaton().trigger(
'commandSubmitted',
'echo "level solved!"'
'echo "level solved! type in \'levels\' to access the next level"'
);
} else {
GlobalStateActions.changeIsAnimating(true);
@ -543,7 +559,7 @@ var Level = Sandbox.extend({
},
die: function() {
React.unmountComponentAtNode(
ReactDOM.unmountComponentAtNode(
document.getElementById('levelToolbarMount')
);
@ -645,7 +661,7 @@ var Level = Sandbox.extend({
};
var method = methodMap[command.get('method')];
if (!method) {
throw new Error('woah we dont support that method yet', method);
throw new Error('woah we don\'t support that method yet', method);
}
method.apply(this, [command, defer]);

View file

@ -1,5 +1,3 @@
var _ = require('underscore');
var GitCommands = require('../git/commands');
var Commands = require('../commands');
var SandboxCommands = require('../sandbox/commands');
@ -27,7 +25,7 @@ ParseWaterfall.prototype.initParseWaterfall = function() {
return;
}
// by deferring the initialization here, we dont require()
// by deferring the initialization here, we don't require()
// level too early (which barfs our init)
this.parseWaterfall = this.options.parseWaterfall || [
Commands.parse,
@ -68,15 +66,17 @@ ParseWaterfall.prototype.addLast = function(which, value) {
};
ParseWaterfall.prototype.expandAllShortcuts = function(commandStr) {
_.each(this.shortcutWaterfall, function(shortcutMap) {
this.shortcutWaterfall.forEach(function(shortcutMap) {
commandStr = this.expandShortcut(commandStr, shortcutMap);
}, this);
return commandStr;
};
ParseWaterfall.prototype.expandShortcut = function(commandStr, shortcutMap) {
_.each(shortcutMap, function(map, vcs) {
_.each(map, function(regex, method) {
Object.keys(shortcutMap).forEach(function(vcs) {
var map = shortcutMap[vcs];
Object.keys(map).forEach(function(method) {
var regex = map[method];
var results = regex.exec(commandStr);
if (results) {
commandStr = vcs + ' ' + method + ' ' + commandStr.slice(results[0].length);
@ -87,13 +87,13 @@ ParseWaterfall.prototype.expandShortcut = function(commandStr, shortcutMap) {
};
ParseWaterfall.prototype.processAllInstants = function(commandStr) {
_.each(this.instantWaterfall, function(instantCommands) {
this.instantWaterfall.forEach(function(instantCommands) {
this.processInstant(commandStr, instantCommands);
}, this);
};
ParseWaterfall.prototype.processInstant = function(commandStr, instantCommands) {
_.each(instantCommands, function(tuple) {
instantCommands.forEach(function(tuple) {
var regex = tuple[0];
var results = regex.exec(commandStr);
if (results) {
@ -109,7 +109,7 @@ ParseWaterfall.prototype.parseAll = function(commandStr) {
}
var toReturn = false;
_.each(this.parseWaterfall, function(parseFunc) {
this.parseWaterfall.forEach(function(parseFunc) {
var results = parseFunc(commandStr);
if (results) {
toReturn = results;
@ -120,4 +120,3 @@ ParseWaterfall.prototype.parseAll = function(commandStr) {
};
exports.ParseWaterfall = ParseWaterfall;

View file

@ -1,9 +1,9 @@
var _ = require('underscore');
var Backbone = require('backbone');
var Errors = require('../util/errors');
var ParseWaterfall = require('../level/parseWaterfall').ParseWaterfall;
var LevelStore = require('../stores/LevelStore');
var intl = require('../intl');
var CommandProcessError = Errors.CommandProcessError;
@ -43,7 +43,7 @@ var Command = Backbone.Model.extend({
},
initDefaults: function() {
// weird things happen with defaults if you dont
// weird things happen with defaults if you don't
// make new objects
this.set('generalArgs', []);
this.set('supportedMap', {});
@ -78,12 +78,13 @@ var Command = Backbone.Model.extend({
var generalArgs = this.getGeneralArgs();
var options = this.getOptionsMap();
generalArgs = _.map(generalArgs, function(arg) {
generalArgs = generalArgs.map(function(arg) {
return this.replaceDotWithHead(arg);
}, this);
var newMap = {};
_.each(options, function(args, key) {
newMap[key] = _.map(args, function(arg) {
Object.keys(options).forEach(function(key) {
var args = options[key];
newMap[key] = Object.values(args).map(function (arg) {
return this.replaceDotWithHead(arg);
}, this);
}, this);
@ -93,7 +94,7 @@ var Command = Backbone.Model.extend({
deleteOptions: function(options) {
var map = this.getOptionsMap();
_.each(options, function(option) {
options.forEach(function(option) {
delete map[option];
}, this);
this.setOptionsMap(map);
@ -126,18 +127,14 @@ var Command = Backbone.Model.extend({
oneArgImpliedHead: function(args, option) {
this.validateArgBounds(args, 0, 1, option);
// and if it's one, add a HEAD to the back
if (args.length === 0) {
args.push('HEAD');
}
this.impliedHead(args, 0);
},
twoArgsImpliedHead: function(args, option) {
// our args we expect to be between 1 and 2
this.validateArgBounds(args, 1, 2, option);
// and if it's one, add a HEAD to the back
if (args.length == 1) {
args.push('HEAD');
}
this.impliedHead(args, 1);
},
oneArgImpliedOrigin: function(args) {
@ -151,6 +148,12 @@ var Command = Backbone.Model.extend({
this.validateArgBounds(args, 0, 2);
},
impliedHead: function(args, min) {
if(args.length == min) {
args.push('HEAD');
}
},
// this is a little utility class to help arg validation that happens over and over again
validateArgBounds: function(args, lower, upper, option) {
var what = (option === undefined) ?
@ -265,15 +268,26 @@ var Command = Backbone.Model.extend({
},
parseAll: function() {
var str = this.get('rawStr');
var results = this.get('parseWaterfall').parseAll(str);
var rawInput = this.get('rawStr');
const aliasMap = LevelStore.getAliasMap();
for (var i = 0; i<Object.keys(aliasMap).length; i++) {
var alias = Object.keys(aliasMap)[i];
var searcher = new RegExp(alias + "(\\s|$)", "g");
if (searcher.test(rawInput)) {
rawInput = rawInput.replace(searcher, aliasMap[alias] + ' ');
break;
}
}
var results = this.get('parseWaterfall').parseAll(rawInput);
if (!results) {
// nothing parsed successfully
return false;
}
_.each(results.toSet, function(obj, key) {
Object.keys(results.toSet).forEach(function(key) {
var obj = results.toSet[key];
// data comes back from the parsing functions like
// options (etc) that need to be set
this.set(key, obj);

View file

@ -1,6 +1,8 @@
var React = require('react');
var PropTypes = require('prop-types');
var CommandView = require('../react_views/CommandView.jsx');
var Main = require('../app');
var React = require('react');
var _subscribeEvents = [
'add',
@ -9,14 +11,9 @@ var _subscribeEvents = [
'all'
];
var CommandHistoryView = React.createClass({
class CommandHistoryView extends React.Component {
propTypes: {
// the backbone command model collection
commandCollection: React.PropTypes.object.isRequired
},
componentDidMount: function() {
componentDidMount() {
for (var i = 0; i < _subscribeEvents.length; i++) {
this.props.commandCollection.on(
_subscribeEvents[i],
@ -27,10 +24,10 @@ var CommandHistoryView = React.createClass({
this.props.commandCollection.on('change', this.scrollDown, this);
Main.getEvents().on('commandScrollDown', this.scrollDown, this);
Main.getEvents().on('clearOldCommands', this.clearOldCommands, this);
},
Main.getEvents().on('clearOldCommands', () => this.clearOldCommands(), this);
}
componentWillUnmount: function() {
componentWillUnmount() {
for (var i = 0; i < _subscribeEvents.length; i++) {
this.props.commandCollection.off(
_subscribeEvents[i],
@ -38,13 +35,13 @@ var CommandHistoryView = React.createClass({
this
);
}
},
}
updateFromCollection: function() {
updateFromCollection() {
this.forceUpdate();
},
}
render: function() {
render() {
var allCommands = [];
this.props.commandCollection.each(function(command, index) {
allCommands.push(
@ -60,9 +57,9 @@ var CommandHistoryView = React.createClass({
{allCommands}
</div>
);
},
}
scrollDown: function() {
scrollDown() {
var cD = document.getElementById('commandDisplay');
var t = document.getElementById('terminal');
@ -81,9 +78,9 @@ var CommandHistoryView = React.createClass({
if (shouldScroll) {
t.scrollTop = t.scrollHeight;
}
},
}
clearOldCommands: function() {
clearOldCommands() {
// go through and get rid of every command that is "processed" or done
var toDestroy = [];
@ -100,6 +97,11 @@ var CommandHistoryView = React.createClass({
this.scrollDown();
}
});
}
CommandHistoryView.propTypes = {
// the backbone command model collection
commandCollection: PropTypes.object.isRequired
};
module.exports = CommandHistoryView;

View file

@ -1,7 +1,9 @@
var React = require('react');
var ReactDOM = require('react-dom');
var PropTypes = require('prop-types');
var reactUtil = require('../util/reactUtil');
var keyMirror = require('react/lib/keyMirror');
var keyMirror = require('../util/keyMirror');
var STATUSES = keyMirror({
inqueue: null,
@ -9,39 +11,18 @@ var STATUSES = keyMirror({
finished: null
});
var CommandView = React.createClass({
class CommandView extends React.Component{
propTypes: {
// the backbone command model
command: React.PropTypes.object.isRequired,
id: React.PropTypes.string,
},
componentDidMount: function() {
componentDidMount() {
this.props.command.on('change', this.updateStateFromModel, this);
this.props.command.on('destroy', this.onModelDestroy, this);
this.updateStateFromModel();
},
}
componentWillUnmount: function() {
componentWillUnmount() {
this.props.command.off('change', this.updateStateFromModel, this);
this.props.command.off('destroy', this.onModelDestroy, this);
},
onModelDestroy: function() {
if (!this.isMounted()) {
return;
}
if (!this.getDOMNode) {
// WTF -- only happens in casperjs tests weirdly
console.error('this.getDOMNode not a function?');
return;
}
React.unmountComponentAtNode(this.getDOMNode().parentNode);
},
updateStateFromModel: function() {
updateStateFromModel() {
var commandJSON = this.props.command.toJSON();
this.setState({
status: commandJSON.status,
@ -49,18 +30,19 @@ var CommandView = React.createClass({
warnings: commandJSON.warnings,
result: commandJSON.result
});
},
}
getInitialState: function() {
return {
constructor(props, context) {
super(props, context);
this.state = {
status: STATUSES.inqueue,
rawStr: 'git commit',
warnings: [],
result: ''
};
},
}
render: function() {
render() {
var commandClass = reactUtil.joinClasses([
this.state.status,
'commandLine',
@ -89,9 +71,9 @@ var CommandView = React.createClass({
</div>
</div>
);
},
}
renderResult: function() {
renderResult() {
if (!this.state.result) {
return null;
}
@ -100,6 +82,17 @@ var CommandView = React.createClass({
var paragraphs = this.state.result.split("\n");
var result = [];
for (var i = 0; i < paragraphs.length; i++) {
if (paragraphs[i].startsWith('https://')) {
result.push(
<a
href={paragraphs[i]}
key={'paragraph_' + i}
dangerouslySetInnerHTML={{
__html: paragraphs[i]
}}
/>
);
} else {
result.push(
<p
key={'paragraph_' + i}
@ -109,14 +102,15 @@ var CommandView = React.createClass({
/>
);
}
}
return (
<div className={'commandLineResult'}>
{result}
</div>
);
},
}
renderFormattedWarnings: function() {
renderFormattedWarnings() {
var warnings = this.state.warnings;
var result = [];
for (var i = 0; i < warnings.length; i++) {
@ -129,6 +123,12 @@ var CommandView = React.createClass({
}
return result;
}
});
};
CommandView.propTypes = {
// the backbone command model
command: PropTypes.object.isRequired,
id: PropTypes.string,
};
module.exports = CommandView;

View file

@ -1,31 +1,27 @@
var React = require('react');
var PropTypes = require('prop-types');
var HelperBarView = require('../react_views/HelperBarView.jsx');
var Main = require('../app');
var React = require('react');
var log = require('../log');
var CommandsHelperBarView = React.createClass({
class CommandsHelperBarView extends React.Component {
propTypes: {
shown: React.PropTypes.bool.isRequired,
onExit: React.PropTypes.func.isRequired
},
render: function() {
render() {
return (
<HelperBarView
items={this.getItems()}
shown={this.props.shown}
/>
);
},
}
fireCommand: function(command) {
fireCommand(command) {
log.viewInteracted('commandHelperBar');
Main.getEventBaton().trigger('commandSubmitted', command);
},
}
getItems: function() {
getItems() {
return [{
text: 'Levels',
onClick: function() {
@ -64,6 +60,11 @@ var CommandsHelperBarView = React.createClass({
}];
}
});
};
CommandsHelperBarView.propTypes = {
shown: PropTypes.bool.isRequired,
onExit: PropTypes.func.isRequired
};
module.exports = CommandsHelperBarView;

View file

@ -1,16 +1,11 @@
var React = require('react');
var PropTypes = require('prop-types');
var reactUtil = require('../util/reactUtil');
var HelperBarView = React.createClass({
class HelperBarView extends React.Component {
propTypes: {
className: React.PropTypes.string,
shown: React.PropTypes.bool.isRequired,
items: React.PropTypes.array.isRequired
},
render: function() {
render() {
var topClassName = reactUtil.joinClasses([
'helperBar',
'transitionAll',
@ -32,9 +27,9 @@ var HelperBarView = React.createClass({
}.bind(this))}
</div>
);
},
}
renderItem: function(item, index) {
renderItem(item, index) {
var testID = item.icon || item.testID ||
item.text.toLowerCase();
if (item.newPageLink) {
@ -63,6 +58,13 @@ var HelperBarView = React.createClass({
);
}
});
};
HelperBarView.propTypes = {
className: PropTypes.string,
shown: PropTypes.bool.isRequired,
items: PropTypes.array.isRequired
};
module.exports = HelperBarView;

View file

@ -1,32 +1,29 @@
var PropTypes = require('prop-types');
var HelperBarView = require('../react_views/HelperBarView.jsx');
var Main = require('../app');
var React = require('react');
var log = require('../log');
var IntlHelperBarView = React.createClass({
class IntlHelperBarView extends React.Component{
propTypes: {
shown: React.PropTypes.bool.isRequired,
onExit: React.PropTypes.func.isRequired
},
render: function() {
render() {
return (
<HelperBarView
items={this.getItems()}
shown={this.props.shown}
/>
);
},
}
fireCommand: function(command) {
fireCommand(command) {
log.viewInteracted('intlSelect');
Main.getEventBaton().trigger('commandSubmitted', command);
this.props.onExit();
},
}
getItems: function() {
getItems() {
return [{
text: 'Git Branching',
testID: 'english',
@ -60,9 +57,21 @@ var IntlHelperBarView = React.createClass({
}, {
text: 'español',
testID: 'spanish',
onClick: function() {
this.fireCommand('locale es_ES; levels');
}.bind(this)
}, {
text: 'argentino',
testID: 'argentinian',
onClick: function() {
this.fireCommand('locale es_AR; levels');
}.bind(this)
}, {
text: 'mexicano',
testID: 'mexican',
onClick: function() {
this.fireCommand('locale es_MX; levels');
}.bind(this)
}, {
text: 'português',
testID: 'portuguese',
@ -93,14 +102,50 @@ var IntlHelperBarView = React.createClass({
onClick: function() {
this.fireCommand('locale uk; levels');
}.bind(this)
}, {
text: 'Tiếng Việt',
testID: 'vietnamese',
onClick: function() {
this.fireCommand('locale vi; levels');
}.bind(this)
}, {
text: 'Galego',
testID: 'galician',
onClick: function() {
this.fireCommand('locale gl; levels');
}.bind(this)
}, {
text: 'Slovensko',
testID: 'slovenian',
onClick: function() {
this.fireCommand('locale sl_SI; levels');
}.bind(this)
}, {
text: 'Polski',
testID: 'polish',
onClick: function() {
this.fireCommand('locale pl; levels');
}.bind(this)
}, {
text: 'தமிழ்',
testID: 'tamil',
onClick: function() {
this.fireCommand('locale ta_IN; levels');
}.bind(this)
}, {
icon: 'signout',
onClick: function() {
this.props.onExit();
}.bind(this)
}];
}
];
}
});
};
IntlHelperBarView.propTypes = {
shown: PropTypes.bool.isRequired,
onExit: PropTypes.func.isRequired
}
module.exports = IntlHelperBarView;

View file

@ -1,31 +1,30 @@
var React = require('react');
var PropTypes = React.PropTypes;
var PropTypes = require('prop-types');
var intl = require('../intl');
var reactUtil = require('../util/reactUtil');
var LevelToolbarView = React.createClass({
class LevelToolbarView extends React.Component {
propTypes: {
name: PropTypes.string.isRequired,
onGoalClick: PropTypes.func.isRequired,
onObjectiveClick: PropTypes.func.isRequired,
parent: PropTypes.object.isRequired
},
getInitialState: function() {
return {
constructor(props, context) {
super(props, context);
this.state = {
isHidden: true,
isGoalExpanded: this.props.parent.getIsGoalExpanded()
};
},
}
componentDidMount: function() {
componentWillUnmount() {
this._isMounted = false;
}
componentDidMount() {
this._isMounted = true;
this.setState({
isHidden: this.props.parent.getIsGoalExpanded()
isHidden: this.props.parent.getIsGoalExpanded(),
isGoalExpanded: this.props.parent.getIsGoalExpanded()
});
this.props.parent.on('goalToggled', function() {
if (!this.isMounted()) {
if (!this._isMounted) {
return;
}
@ -33,9 +32,9 @@ var LevelToolbarView = React.createClass({
isGoalExpanded: this.props.parent.getIsGoalExpanded()
});
}.bind(this));
},
}
render: function() {
render() {
return (
<div className={reactUtil.joinClasses([
'toolbar',
@ -78,6 +77,13 @@ var LevelToolbarView = React.createClass({
);
}
});
};
LevelToolbarView.propTypes = {
name: PropTypes.string.isRequired,
onGoalClick: PropTypes.func.isRequired,
onObjectiveClick: PropTypes.func.isRequired,
parent: PropTypes.object.isRequired
}
module.exports = LevelToolbarView;

View file

@ -14,15 +14,16 @@ var BARS = keyMirror({
COMMANDS: null
});
var MainHelperBarView = React.createClass({
class MainHelperBarView extends React.Component {
getInitialState: function() {
return {
constructor(props, context) {
super(props, context);
this.state = {
shownBar: BARS.SELF
};
},
}
render: function() {
render() {
return (
<div>
<HelperBarView
@ -32,23 +33,23 @@ var MainHelperBarView = React.createClass({
/>
<CommandsHelperBarView
shown={this.state.shownBar === BARS.COMMANDS}
onExit={this.showSelf}
onExit={this.showSelf.bind(this)}
/>
<IntlHelperBarView
shown={this.state.shownBar === BARS.INTL}
onExit={this.showSelf}
onExit={this.showSelf.bind(this)}
/>
</div>
);
},
}
showSelf: function() {
showSelf() {
this.setState({
shownBar: BARS.SELF
});
},
}
getItems: function() {
getItems() {
return [{
icon: 'question-sign',
onClick: function() {
@ -74,6 +75,6 @@ var MainHelperBarView = React.createClass({
}];
}
});
};
module.exports = MainHelperBarView;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var util = require('../util');
var constants = require('../util/constants');
@ -9,6 +8,7 @@ var Errors = require('../util/errors');
var CommandProcessError = Errors.CommandProcessError;
var LocaleStore = require('../stores/LocaleStore');
var LocaleActions = require('../actions/LocaleActions');
var LevelStore = require('../stores/LevelStore');
var GlobalStateStore = require('../stores/GlobalStateStore');
var GlobalStateActions = require('../actions/GlobalStateActions');
var GitError = Errors.GitError;
@ -16,12 +16,12 @@ var Warning = Errors.Warning;
var CommandResult = Errors.CommandResult;
var instantCommands = [
[/^ls/, function() {
[/^ls( |$)/, function() {
throw new CommandResult({
msg: intl.str('ls-command')
});
}],
[/^cd/, function() {
[/^cd( |$)/, function() {
throw new CommandResult({
msg: intl.str('cd-command')
});
@ -51,6 +51,21 @@ var instantCommands = [
msg: lines.join('\n')
});
}],
[/^alias (\w+)="(.+)"$/, function(bits) {
const alias = bits[1];
const expansion = bits[2];
LevelStore.addToAliasMap(alias, expansion);
throw new CommandResult({
msg: 'Set alias "'+alias+'" to "'+expansion+'"',
});
}],
[/^unalias (\w+)$/, function(bits) {
const alias = bits[1];
LevelStore.removeFromAliasMap(alias);
throw new CommandResult({
msg: 'Removed alias "'+alias+'"',
});
}],
[/^locale (\w+)$/, function(bits) {
LocaleActions.changeLocale(bits[1]);
throw new CommandResult({
@ -69,6 +84,12 @@ var instantCommands = [
msg: intl.str('flip-tree-command')
});
}],
[/^disableLevelInstructions$/, function() {
GlobalStateActions.disableLevelInstructions();
throw new CommandResult({
msg: intl.todo('Level instructions disabled'),
});
}],
[/^refresh$/, function() {
var events = require('../app').getEvents();
@ -98,7 +119,8 @@ var instantCommands = [
intl.str('show-all-commands'),
'<br/>'
];
_.each(allCommands, function(regex, command) {
Object.keys(allCommands)
.forEach(function(command) {
lines.push(command);
});
@ -134,17 +156,20 @@ var getAllCommands = function() {
'mobileAlert'
];
var allCommands = _.extend(
var allCommands = Object.assign(
{},
require('../level').regexMap,
regexMap
);
_.each(Commands.commands.getRegexMap(), function(map, vcs) {
_.each(map, function(regex, method) {
var mRegexMap = Commands.commands.getRegexMap();
Object.keys(mRegexMap).forEach(function(vcs) {
var map = mRegexMap[vcs];
Object.keys(map).forEach(function(method) {
var regex = map[method];
allCommands[vcs + ' ' + method] = regex;
});
});
_.each(toDelete, function(key) {
toDelete.forEach(function(key) {
delete allCommands[key];
});

View file

@ -228,12 +228,21 @@ var Sandbox = Backbone.View.extend({
var url =
'https://learngitbranching.js.org/?NODEMO&command=importTreeNow%20' + escape(treeJSON);
command.setResult(
intl.todo('Here is a link to the current state of the tree: ') + url
intl.todo('Here is a link to the current state of the tree: ') + '\n' + url
);
command.finishWith(deferred);
},
resetSolved: function(command, deferred) {
if (command.get('regexResults').input !== 'reset solved --confirm') {
command.set('error', new Errors.GitError({
msg: 'Reset solved will mark each level as not yet solved; because ' +
'this is a destructive command, please pass in --confirm to execute',
}));
command.finishWith(deferred);
return;
}
LevelActions.resetLevelsSolved();
command.addWarning(
intl.str('solved-map-reset')

View file

@ -4,8 +4,6 @@ var AppConstants = require('../constants/AppConstants');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ActionTypes = AppConstants.ActionTypes;
var COMMAND_HISTORY_KEY = 'lgb_CommandHistory';
var COMMAND_HISTORY_MAX_LENGTH = 100;
@ -38,7 +36,7 @@ function _saveToLocalStorage() {
}
}
var CommandLineStore = assign(
var CommandLineStore = Object.assign(
{},
EventEmitter.prototype,
AppConstants.StoreSubscribePrototype,

View file

@ -4,15 +4,14 @@ var AppConstants = require('../constants/AppConstants');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ActionTypes = AppConstants.ActionTypes;
var _isAnimating = false;
var _flipTreeY = false;
var _numLevelsSolved = 0;
var _disableLevelInstructions = false;
var GlobalStateStore = assign(
var GlobalStateStore = Object.assign(
{},
EventEmitter.prototype,
AppConstants.StoreSubscribePrototype,
@ -29,6 +28,10 @@ AppConstants.StoreSubscribePrototype,
return _numLevelsSolved;
},
getShouldDisableLevelInstructions: function() {
return _disableLevelInstructions;
},
dispatchToken: AppDispatcher.register(function(payload) {
var action = payload.action;
var shouldInform = false;
@ -46,6 +49,10 @@ AppConstants.StoreSubscribePrototype,
_numLevelsSolved++;
shouldInform = true;
break;
case ActionTypes.DISABLE_LEVEL_INSTRUCTIONS:
_disableLevelInstructions = true;
shouldInform = true;
break;
}
if (shouldInform) {

View file

@ -3,19 +3,43 @@
var AppConstants = require('../constants/AppConstants');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var _ = require('underscore');
var assign = require('object-assign');
var levelSequences = require('../../levels').levelSequences;
var sequenceInfo = require('../../levels').sequenceInfo;
var util = require('../util');
var ActionTypes = AppConstants.ActionTypes;
var SOLVED_MAP_STORAGE_KEY = 'solvedMap';
var ALIAS_STORAGE_KEY = 'aliasMap';
var _levelMap = {};
var _solvedMap = {};
var _sequences = [];
if (!util.isBrowser()) {
// https://stackoverflow.com/a/26177872/6250402
var storage = {};
var localStorage = {
setItem: function(key, value) {
storage[key] = value || '';
},
getItem: function(key) {
return key in storage ? storage[key] : null;
},
removeItem: function(key) {
delete storage[key];
},
get length() {
return Object.keys(storage).length;
},
key: function(i) {
const keys = Object.keys(storage);
return keys[i] || null;
}
};
} else {
var localStorage = window.localStorage;
}
try {
_solvedMap = JSON.parse(
localStorage.getItem(SOLVED_MAP_STORAGE_KEY) || '{}'
@ -32,6 +56,26 @@ function _syncToStorage() {
}
}
function getAliasMap() {
try {
return JSON.parse(localStorage.getItem(ALIAS_STORAGE_KEY) || '{}') || {};
} catch (e) {
return {};
}
}
function addToAliasMap(alias, expansion) {
const aliasMap = getAliasMap();
aliasMap[alias] = expansion;
localStorage.setItem(ALIAS_STORAGE_KEY, JSON.stringify(aliasMap));
}
function removeFromAliasMap(alias) {
const aliasMap = getAliasMap();
delete aliasMap[alias];
localStorage.setItem(ALIAS_STORAGE_KEY, JSON.stringify(aliasMap));
}
var validateLevel = function(level) {
level = level || {};
var requiredFields = [
@ -41,7 +85,7 @@ var validateLevel = function(level) {
'solutionCommand'
];
_.each(requiredFields, function(field) {
requiredFields.forEach(function(field) {
if (level[field] === undefined) {
console.log(level);
throw new Error('I need this field for a level: ' + field);
@ -52,18 +96,19 @@ var validateLevel = function(level) {
/**
* Unpack the level sequences.
*/
_.each(levelSequences, function(levels, levelSequenceName) {
Object.keys(levelSequences).forEach(function(levelSequenceName) {
var levels = levelSequences[levelSequenceName];
_sequences.push(levelSequenceName);
if (!levels || !levels.length) {
throw new Error('no empty sequences allowed');
}
// for this particular sequence...
_.each(levels, function(level, index) {
levels.forEach(function(level, index) {
validateLevel(level);
var id = levelSequenceName + String(index + 1);
var compiledLevel = assign(
var compiledLevel = Object.assign(
{},
level,
{
@ -79,17 +124,21 @@ _.each(levelSequences, function(levels, levelSequenceName) {
});
});
var LevelStore = assign(
var LevelStore = Object.assign(
{},
EventEmitter.prototype,
AppConstants.StoreSubscribePrototype,
{
getAliasMap: getAliasMap,
addToAliasMap: addToAliasMap,
removeFromAliasMap: removeFromAliasMap,
getSequenceToLevels: function() {
return levelSequences;
},
getSequences: function() {
return _.keys(levelSequences);
return Object.keys(levelSequences);
},
getLevelsInSequence: function(sequenceName) {
@ -109,11 +158,11 @@ AppConstants.StoreSubscribePrototype,
getNextLevel: function(id) {
if (!_levelMap[id]) {
console.warn('that level doesnt exist!!!');
console.warn('that level doesn\'t exist!!!');
return null;
}
// meh, this method could be better. It's a tradeoff between
// meh, this method could be better. It's a trade-off between
// having the sequence structure be really simple JSON
// and having no connectivity information between levels, which means
// you have to build that up yourself on every query
@ -138,7 +187,7 @@ AppConstants.StoreSubscribePrototype,
isLevelSolved: function(levelID) {
if (!_levelMap[levelID]) {
throw new Error('that level doesnt exist!');
throw new Error('that level doesn\'t exist!');
}
return !!_solvedMap[levelID];
},

View file

@ -2,10 +2,9 @@
var AppConstants = require('../constants/AppConstants');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var util = require('../util');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ActionTypes = AppConstants.ActionTypes;
var DEFAULT_LOCALE = 'en_US';
@ -21,15 +20,26 @@ var langLocaleMap = {
de: 'de_DE',
pt: 'pt_BR',
ru: 'ru_RU',
uk: 'uk'
uk: 'uk',
vi: 'vi',
sl: 'sl_SI',
pl: 'pl',
ta: 'ta_IN'
};
var headerLocaleMap = {
'zh-CN': 'zh_CN',
'zh-TW': 'zh_TW',
'pt-BR': 'pt_BR'
'pt-BR': 'pt_BR',
'es-MX': 'es_MX',
'es-ES': 'es_ES',
'sl-SI': 'sl_SI'
};
var supportedLocalesList = Object.values(langLocaleMap)
.concat(Object.values(headerLocaleMap))
.filter(function (value, index, self) { return self.indexOf(value) === index;});
function _getLocaleFromHeader(langString) {
var languages = langString.split(',');
var desiredLocale;
@ -51,7 +61,7 @@ function _getLocaleFromHeader(langString) {
}
var _locale = DEFAULT_LOCALE;
var LocaleStore = assign(
var LocaleStore = Object.assign(
{},
EventEmitter.prototype,
AppConstants.StoreSubscribePrototype,
@ -62,20 +72,25 @@ AppConstants.StoreSubscribePrototype,
},
getLangLocaleMap: function() {
return assign({}, langLocaleMap);
return Object.assign({}, langLocaleMap);
},
getHeaderLocaleMap: function() {
return assign({}, headerLocaleMap);
return Object.assign({}, headerLocaleMap);
},
getLocale: function() {
return _locale;
},
getSupportedLocales: function() {
return supportedLocalesList.slice();
},
dispatchToken: AppDispatcher.register(function(payload) {
var action = payload.action;
var shouldInform = false;
var oldLocale = _locale;
switch (action.type) {
case ActionTypes.CHANGE_LOCALE:
@ -91,6 +106,12 @@ AppConstants.StoreSubscribePrototype,
break;
}
if (util.isBrowser() && oldLocale !== _locale) {
var url = new URL(document.location.href);
url.searchParams.set('locale', _locale);
window.history.replaceState({}, '', url.href);
}
if (shouldInform) {
LocaleStore.emit(AppConstants.CHANGE_EVENT);
}

17
src/js/util/debounce.js Normal file
View file

@ -0,0 +1,17 @@
module.exports = function(func, time, immediate) {
var timeout;
return function() {
var later = function() {
timeout = null;
if (!immediate) {
func.apply(this, arguments);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, time);
if (callNow) {
func.apply(this, arguments);
}
};
};

View file

@ -30,7 +30,7 @@ var toGlobalize = {
Level: require('../level'),
Sandbox: require('../sandbox/'),
GitDemonstrationView: require('../views/gitDemonstrationView'),
Markdown: require('markdown'),
Markdown: require('marked'),
LevelDropdownView: require('../views/levelDropdownView'),
BuilderViews: require('../views/builderViews'),
Util: require('../util/index'),
@ -59,4 +59,3 @@ $(document).ready(function() {
return toGlobalize.Main.getSandbox().mainVis.gitEngine.printAndCopyTree();
};
});

View file

@ -27,7 +27,7 @@ EventBaton.prototype.sliceOffArgs = function(num, args) {
};
EventBaton.prototype.trigger = function(name) {
// arguments is weird and doesnt do slice right
// arguments is weird and doesn't do slice right
var argsToApply = this.sliceOffArgs(1, arguments);
var listeners = this.eventMap[name];
@ -76,7 +76,7 @@ EventBaton.prototype.passBatonBack = function(name, func, context, args) {
}
});
if (indexBefore === undefined) {
throw new Error('you are the last baton holder! or i didnt find you');
throw new Error('you are the last baton holder! or i didn\'t find you');
}
var toCallObj = listeners[indexBefore];
@ -105,7 +105,7 @@ EventBaton.prototype.releaseBaton = function(name, func, context) {
if (!found) {
console.log('did not find that function', func, context, name, arguments);
console.log(this.eventMap);
throw new Error('cant releasebaton if yu dont have it');
throw new Error('can\'t releasebaton if you don\'t have it');
}
this.eventMap[name] = newListeners;
};

View file

@ -1,3 +1,6 @@
var { readdirSync, lstatSync } = require('fs');
var { join } = require('path');
var escapeString = require('../util/escapeString');
var constants = require('../util/constants');
@ -24,7 +27,8 @@ exports.splitTextCommand = function(value, func, context) {
.replace(/^(\s+)/, '')
.replace(/(\s+)$/, '')
.replace(/&quot;/g, '"')
.replace(/&#x27;/g, "'");
.replace(/&#x27;/g, "'")
.replace(/&#x2F;/g, "/");
if (index > 0 && !command.length) {
return;
@ -55,3 +59,16 @@ exports.genParseCommand = function(regexMap, eventName) {
};
};
};
exports.readDirDeep = function(dir) {
var paths = [];
readdirSync(dir).forEach(function(path) {
var aPath = join(dir, path);
if (lstatSync(aPath).isDirectory()) {
paths.push(...exports.readDirDeep(aPath));
} else {
paths.push(aPath);
}
});
return paths;
};

13
src/js/util/throttle.js Normal file
View file

@ -0,0 +1,13 @@
module.exports = function(func, time) {
var wait = false;
return function() {
if (!wait) {
func.apply(this, arguments);
wait = true;
setTimeout(function() {
wait = false;
}, time);
}
};
};

View file

@ -1,7 +1,9 @@
var _ = require('underscore');
var Q = require('q');
var marked = require('marked');
var Views = require('../views');
var throttle = require('../util/throttle');
var ModalTerminal = Views.ModalTerminal;
var ContainedBase = Views.ContainedBase;
@ -97,7 +99,7 @@ var MarkdownGrabber = ContainedBase.extend({
keyup: function() {
if (!this.throttledPreview) {
this.throttledPreview = _.throttle(
this.throttledPreview = throttle(
this.updatePreview.bind(this),
500
);
@ -121,7 +123,7 @@ var MarkdownGrabber = ContainedBase.extend({
updatePreview: function() {
var raw = this.getRawText();
var HTML = require('markdown').markdown.toHTML(raw);
var HTML = marked(raw);
this.$('div.insidePreview').html(HTML);
}
});
@ -179,7 +181,7 @@ var DemonstrationBuilder = ContainedBase.extend({
this.deferred = options.deferred || Q.defer();
if (options.fromObj) {
var toEdit = options.fromObj.options;
options = _.extend(
options = Object.assign(
{},
options,
toEdit,
@ -295,7 +297,7 @@ var MultiViewBuilder = ContainedBase.extend({
this.JSON = {
views: this.getChildViews(),
supportedViews: _.keys(this.typeToConstructor)
supportedViews: Object.keys(this.typeToConstructor)
};
this.container = new ModalTerminal({
@ -334,7 +336,7 @@ var MultiViewBuilder = ContainedBase.extend({
this.addChildViewObj(newView);
}.bind(this))
.fail(function() {
// they dont want to add the view apparently, so just return
// they don't want to add the view apparently, so just return
})
.done();
},
@ -416,4 +418,3 @@ exports.DemonstrationBuilder = DemonstrationBuilder;
exports.TextGrabber = TextGrabber;
exports.MultiViewBuilder = MultiViewBuilder;
exports.MarkdownPresenter = MarkdownPresenter;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var Main = require('../app');
@ -173,7 +172,7 @@ var CommandPromptView = Backbone.View.extend({
which.reverse();
var str = '';
_.each(which, function(text) {
which.forEach(function(text) {
str += text + ';';
}, this);
@ -202,4 +201,3 @@ var CommandPromptView = Backbone.View.extend({
});
exports.CommandPromptView = CommandPromptView;

View file

@ -1,6 +1,7 @@
var _ = require('underscore');
var Q = require('q');
var Backbone = require('backbone');
var marked = require('marked');
var util = require('../util');
var intl = require('../intl');
@ -25,7 +26,7 @@ var GitDemonstrationView = ContainedBase.extend({
initialize: function(options) {
options = options || {};
this.options = options;
this.JSON = _.extend(
this.JSON = Object.assign(
{
beforeMarkdowns: [
'## Git Commits',
@ -43,7 +44,7 @@ var GitDemonstrationView = ContainedBase.extend({
);
var convert = function(markdowns) {
return require('markdown').markdown.toHTML(markdowns.join('\n'));
return marked(markdowns.join('\n'));
};
this.JSON.beforeHTML = convert(this.JSON.beforeMarkdowns);
@ -55,7 +56,7 @@ var GitDemonstrationView = ContainedBase.extend({
this.render();
this.checkScroll();
this.navEvents = _.clone(Backbone.Events);
this.navEvents = Object.assign({}, Backbone.Events);
this.navEvents.on('positive', this.positive, this);
this.navEvents.on('negative', this.negative, this);
this.keyboardListener = new KeyboardListener({
@ -83,9 +84,9 @@ var GitDemonstrationView = ContainedBase.extend({
},
checkScroll: function() {
var children = this.$('div.demonstrationText').children();
var heights = _.map(children, function(child) { return child.clientHeight; });
var totalHeight = _.reduce(heights, function(a, b) { return a + b; });
var children = this.$('div.demonstrationText').children().toArray();
var heights = children.map(function(child) { return child.clientHeight; });
var totalHeight = heights.reduce(function(a, b) { return a + b; });
if (totalHeight < this.$('div.demonstrationText').height()) {
this.$('div.demonstrationText').addClass('noLongText');
}
@ -129,9 +130,9 @@ var GitDemonstrationView = ContainedBase.extend({
positive: function() {
if (this.demonstrated || !this.hasControl) {
// dont do anything if we are demonstrating, and if
// don't do anything if we are demonstrating, and if
// we receive a meta nav event and we aren't listening,
// then dont do anything either
// then don't do anything either
return;
}
this.demonstrated = true;
@ -168,7 +169,7 @@ var GitDemonstrationView = ContainedBase.extend({
var chainDeferred = Q.defer();
var chainPromise = chainDeferred.promise;
_.each(commands, function(command, index) {
commands.forEach(function(command, index) {
chainPromise = chainPromise.then(function() {
var myDefer = Q.defer();
this.mainVis.gitEngine.dispatch(command, myDefer);
@ -244,4 +245,3 @@ var GitDemonstrationView = ContainedBase.extend({
});
exports.GitDemonstrationView = GitDemonstrationView;

View file

@ -1,12 +1,15 @@
var _ = require('underscore');
var Q = require('q');
var Backbone = require('backbone');
var marked = require('marked');
var Main = require('../app');
var intl = require('../intl');
var log = require('../log');
var Constants = require('../util/constants');
var KeyboardListener = require('../util/keyboard').KeyboardListener;
var debounce = require('../util/debounce');
var throttle = require('../util/throttle');
var BaseView = Backbone.View.extend({
getDestination: function() {
@ -86,7 +89,7 @@ var GeneralButton = ContainedBase.extend({
initialize: function(options) {
options = options || {};
this.navEvents = options.navEvents || _.clone(Backbone.Events);
this.navEvents = options.navEvents || Object.assign({}, Backbone.Events);
this.destination = options.destination;
if (!this.destination) {
this.container = new ModalTerminal();
@ -106,7 +109,7 @@ var GeneralButton = ContainedBase.extend({
click: function() {
if (!this.clickFunc) {
this.clickFunc = _.throttle(
this.clickFunc = throttle(
this.sendClick.bind(this),
500
);
@ -136,8 +139,8 @@ var ConfirmCancelView = ResolveRejectBase.extend({
this.destination = options.destination;
this.deferred = options.deferred || Q.defer();
this.JSON = {
confirm: options.confirm || 'Confirm',
cancel: options.cancel || 'Cancel'
confirm: options.confirm || intl.str('confirm-button'),
cancel: options.cancel || intl.str('cancel-button')
};
this.render();
@ -160,7 +163,7 @@ var LeftRightView = PositiveNegativeBase.extend({
// events system to add support for git demonstration view taking control of the
// click events
this.pipeEvents = options.events;
this.navEvents = _.clone(Backbone.Events);
this.navEvents = Object.assign({}, Backbone.Events);
this.JSON = {
showLeft: (options.showLeft === undefined) ? true : options.showLeft,
@ -168,7 +171,7 @@ var LeftRightView = PositiveNegativeBase.extend({
};
this.render();
// For some weird reason backbone events arent working anymore so
// For some weird reason backbone events aren't working anymore so
// im going to just wire this up manually
this.$('div.right').click(this.positive.bind(this));
this.$('div.left').click(this.negative.bind(this));
@ -208,7 +211,7 @@ var ModalView = Backbone.View.extend({
// add ourselves to the DOM
this.$el.html(this.template({}));
$('body').append(this.el);
// this doesnt necessarily show us though...
// this doesn't necessarily show us though...
},
stealKeyboard: function() {
@ -305,7 +308,7 @@ var ModalTerminal = ContainedBase.extend({
initialize: function(options) {
options = options || {};
this.navEvents = options.events || _.clone(Backbone.Events);
this.navEvents = options.events || Object.assign({}, Backbone.Events);
this.container = new ModalView();
this.JSON = {
@ -354,7 +357,7 @@ var ModalAlert = ContainedBase.extend({
render: function() {
var HTML = (this.JSON.markdown) ?
require('markdown').markdown.toHTML(this.JSON.markdown) :
marked(this.JSON.markdown) :
this.template(this.JSON);
// one more hack -- allow adding custom random HTML if specified
if (this.options._dangerouslyInsertHTML) {
@ -372,7 +375,7 @@ var ConfirmCancelTerminal = Backbone.View.extend({
options = options || {};
this.deferred = options.deferred || Q.defer();
this.modalAlert = new ModalAlert(_.extend(
this.modalAlert = new ModalAlert(Object.assign(
{},
{ markdown: '#you sure?' },
options
@ -395,7 +398,7 @@ var ConfirmCancelTerminal = Backbone.View.extend({
}.bind(this));
// also setup keyboard
this.navEvents = _.clone(Backbone.Events);
this.navEvents = Object.assign({}, Backbone.Events);
this.navEvents.on('positive', this.positive, this);
this.navEvents.on('negative', this.negative, this);
this.keyboardListener = new KeyboardListener({
@ -470,7 +473,7 @@ var NextLevelConfirm = ConfirmCancelTerminal.extend({
'</p>';
}
options = _.extend(
options = Object.assign(
{},
options,
{
@ -580,7 +583,7 @@ var CanvasTerminalHolder = BaseView.extend({
// If the entire window gets resized such that the terminal is outside the view, then
// move it back into the view, and expand/shrink it vertically as necessary.
$(window).on('resize', _.debounce(this.recalcLayout.bind(this), 300));
$(window).on('resize', debounce(this.recalcLayout.bind(this), 300));
if (options.additionalClass) {
this.$el.addClass(options.additionalClass);

View file

@ -4,6 +4,7 @@ var Backbone = require('backbone');
var LocaleStore = require('../stores/LocaleStore');
var util = require('../util');
var debounce = require('../util/debounce');
var intl = require('../intl');
var log = require('../log');
var KeyboardListener = require('../util/keyboard').KeyboardListener;
@ -40,8 +41,8 @@ var LevelDropdownView = ContainedBase.extend({
}]
};
this.navEvents = _.clone(Backbone.Events);
this.navEvents.on('clickedID', _.debounce(
this.navEvents = Object.assign({}, Backbone.Events);
this.navEvents.on('clickedID', debounce(
this.loadLevelID.bind(this),
300,
true
@ -211,7 +212,7 @@ var LevelDropdownView = ContainedBase.extend({
},
getTabIndex: function() {
var ids = _.map(this.JSON.tabs, function(tab) {
var ids = this.JSON.tabs.map(function(tab) {
return tab.id;
});
return ids.indexOf(this.JSON.selectedTab);
@ -235,7 +236,7 @@ var LevelDropdownView = ContainedBase.extend({
},
getSequencesOnTab: function() {
return _.filter(this.sequences, function(sequenceName) {
return this.sequences.filter(function(sequenceName) {
var tab = LEVELS.getTabForSequence(sequenceName);
return tab === this.JSON.selectedTab;
}, this);
@ -292,7 +293,7 @@ var LevelDropdownView = ContainedBase.extend({
$(selector).toggleClass('selected', value);
// also go find the series and update the about
_.each(this.seriesViews, function(view) {
this.seriesViews.forEach(function(view) {
if (view.levelIDs.indexOf(id) === -1) {
return;
}
@ -343,14 +344,14 @@ var LevelDropdownView = ContainedBase.extend({
},
updateSolvedStatus: function() {
_.each(this.seriesViews, function(view) {
this.seriesViews.forEach(function(view) {
view.updateSolvedStatus();
}, this);
},
buildSequences: function() {
this.seriesViews = [];
_.each(this.getSequencesOnTab(), function(sequenceName) {
this.getSequencesOnTab().forEach(function(sequenceName) {
this.seriesViews.push(new SeriesView({
destination: this.$el,
name: sequenceName,
@ -377,7 +378,7 @@ var SeriesView = BaseView.extend({
this.levelIDs = [];
var firstLevelInfo = null;
_.each(this.levels, function(level) {
this.levels.forEach(function(level) {
if (firstLevelInfo === null) {
firstLevelInfo = this.formatLevelAbout(level.id);
}
@ -444,4 +445,3 @@ var SeriesView = BaseView.extend({
});
exports.LevelDropdownView = LevelDropdownView;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Q = require('q');
var Backbone = require('backbone');
@ -10,6 +9,7 @@ var BuilderViews = require('../views/builderViews');
var MarkdownPresenter = BuilderViews.MarkdownPresenter;
var KeyboardListener = require('../util/keyboard').KeyboardListener;
var debounce = require('../util/debounce');
var MultiView = Backbone.View.extend({
tagName: 'div',
@ -48,7 +48,7 @@ var MultiView = Backbone.View.extend({
this.childViews = [];
this.currentIndex = 0;
this.navEvents = _.clone(Backbone.Events);
this.navEvents = Object.assign({}, Backbone.Events);
this.navEvents.on('negative', this.getNegFunc(), this);
this.navEvents.on('positive', this.getPosFunc(), this);
this.navEvents.on('quit', this.finish, this);
@ -84,13 +84,13 @@ var MultiView = Backbone.View.extend({
},
getPosFunc: function() {
return _.debounce(function() {
return debounce(function() {
this.navForward();
}.bind(this), this.navEventDebounce, true);
},
getNegFunc: function() {
return _.debounce(function() {
return debounce(function() {
this.navBackward();
}.bind(this), this.navEventDebounce, true);
},
@ -142,7 +142,7 @@ var MultiView = Backbone.View.extend({
// other views will take if they need to
this.keyboardListener.mute();
_.each(this.childViews, function(childView) {
this.childViews.forEach(function(childView) {
childView.die();
});
@ -159,7 +159,7 @@ var MultiView = Backbone.View.extend({
if (!this.typeToConstructor[type]) {
throw new Error('no constructor for type "' + type + '"');
}
var view = new this.typeToConstructor[type](_.extend(
var view = new this.typeToConstructor[type](Object.assign(
{},
viewJSON.options,
{ wait: true }
@ -183,7 +183,7 @@ var MultiView = Backbone.View.extend({
render: function() {
// go through each and render... show the first
_.each(this.childViewJSONs, function(childViewJSON, index) {
this.childViewJSONs.forEach(function(childViewJSON, index) {
var childView = this.createChildView(childViewJSON);
this.childViews.push(childView);
this.addNavToView(childView, index);
@ -192,4 +192,3 @@ var MultiView = Backbone.View.extend({
});
exports.MultiView = MultiView;

View file

@ -7,6 +7,17 @@ var ModalTerminal = require('../views').ModalTerminal;
var ContainedBase = require('../views').ContainedBase;
var ConfirmCancelView = require('../views').ConfirmCancelView;
require('jquery-ui/ui/widget');
require('jquery-ui/ui/scroll-parent');
require('jquery-ui/ui/data');
require('jquery-ui/ui/widgets/mouse');
require('jquery-ui/ui/ie');
require('jquery-ui/ui/widgets/sortable');
require('jquery-ui/ui/plugin');
require('jquery-ui/ui/safe-active-element');
require('jquery-ui/ui/safe-blur');
require('jquery-ui/ui/widgets/draggable');
var InteractiveRebaseView = ContainedBase.extend({
tagName: 'div',
template: _.template($('#interactive-rebase-template').html()),
@ -19,7 +30,7 @@ var InteractiveRebaseView = ContainedBase.extend({
this.rebaseEntries = new RebaseEntryCollection();
options.toRebase.reverse();
_.each(options.toRebase, function(commit) {
options.toRebase.forEach(function(commit) {
var id = commit.get('id');
this.rebaseMap[id] = commit;
@ -63,7 +74,7 @@ var InteractiveRebaseView = ContainedBase.extend({
// now get the real array
var toRebase = [];
_.each(uiOrder, function(id) {
uiOrder.forEach(function(id) {
// the model pick check
if (this.entryObjMap[id].get('pick')) {
toRebase.unshift(this.rebaseMap[id]);
@ -78,7 +89,7 @@ var InteractiveRebaseView = ContainedBase.extend({
render: function() {
var json = {
num: _.keys(this.rebaseMap).length,
num: Object.keys(this.rebaseMap).length,
solutionOrder: this.options.initialCommitOrdering
};
@ -164,7 +175,6 @@ var RebaseEntryView = Backbone.View.extend({
},
render: function() {
var json = this.model.toJSON();
this.$el.append(this.template(this.model.toJSON()));
// hacky :( who would have known jquery barfs on ids with %'s and quotes

View file

@ -55,7 +55,7 @@ var AnimationQueue = Backbone.Model.extend({
},
add: function(animation) {
if (!animation instanceof Animation) {
if (!(animation instanceof Animation)) {
throw new Error("Need animation not something else");
}

View file

@ -1,8 +1,8 @@
var _ = require('underscore');
var Q = require('q');
var intl = require('../intl');
var GRAPHICS = require('../util/constants').GRAPHICS;
var debounce = require('../util/debounce');
var GlobalStateStore = require('../stores/GlobalStateStore');
var VisNode = require('../visuals/visNode').VisNode;
@ -58,7 +58,7 @@ GitVisuals.prototype.defer = function(action) {
};
GitVisuals.prototype.deferFlush = function() {
_.each(this.deferred, function(action) {
this.deferred.forEach(function(action) {
action();
}, this);
this.deferred = [];
@ -68,21 +68,21 @@ GitVisuals.prototype.resetAll = function() {
// make sure to copy these collections because we remove
// items in place and underscore is too dumb to detect length change
var edges = this.visEdgeCollection.toArray();
_.each(edges, function(visEdge) {
edges.forEach(function(visEdge) {
visEdge.remove();
}, this);
var branches = this.visBranchCollection.toArray();
_.each(branches, function(visBranch) {
branches.forEach(function(visBranch) {
visBranch.remove();
}, this);
var tags = this.visTagCollection.toArray();
_.each(tags, function(visTag) {
tags.forEach(function(visTag) {
visTag.remove();
}, this);
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
visNode.remove();
}, this);
@ -98,7 +98,7 @@ GitVisuals.prototype.resetAll = function() {
GitVisuals.prototype.tearDown = function() {
this.resetAll();
this.paper.remove();
// Unregister the refresh tree listener so we dont accumulate
// Unregister the refresh tree listener so we don't accumulate
// these over time. However we aren't calling tearDown in
// some places... but this is an improvement
var Main = require('../app');
@ -206,7 +206,7 @@ GitVisuals.prototype.animateAllAttrKeys = function(keys, attr, speed, easing) {
this.visBranchCollection.each(animate);
this.visEdgeCollection.each(animate);
this.visTagCollection.each(animate);
_.each(this.visNodeMap, animate);
Object.values(this.visNodeMap).forEach(animate);
var time = (speed !== undefined) ? speed : GRAPHICS.defaultAnimationTime;
setTimeout(function() {
@ -240,7 +240,7 @@ GitVisuals.prototype.finishAnimation = function(speed) {
opacity: 0,
'font-weight': 500,
'font-size': '32pt',
'font-family': 'Monaco, Courier, font-monospace',
'font-family': 'Menlo, Monaco, Consolas, \'Droid Sans Mono\', monospace',
stroke: '#000',
'stroke-width': 2,
fill: '#000'
@ -321,7 +321,7 @@ GitVisuals.prototype.finishAnimation = function(speed) {
GitVisuals.prototype.explodeNodes = function(speed) {
var deferred = Q.defer();
var funcs = [];
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
funcs.push(visNode.getExplodeStepFunc(speed));
});
@ -332,7 +332,7 @@ GitVisuals.prototype.explodeNodes = function(speed) {
// are called unnecessarily when they have almost
// zero speed. would be interesting to see performance differences
var keepGoing = [];
_.each(funcs, function(func) {
funcs.forEach(function(func) {
if (func()) {
keepGoing.push(func);
}
@ -354,12 +354,12 @@ GitVisuals.prototype.explodeNodes = function(speed) {
GitVisuals.prototype.animateAllFromAttrToAttr = function(fromSnapshot, toSnapshot, idsToOmit) {
var animate = function(obj) {
var id = obj.getID();
if (_.include(idsToOmit, id)) {
if (idsToOmit.includes(id)) {
return;
}
if (!fromSnapshot[id] || !toSnapshot[id]) {
// its actually ok it doesnt exist yet
// its actually ok it doesn't exist yet
return;
}
obj.animateFromAttrToAttr(fromSnapshot[id], toSnapshot[id]);
@ -368,7 +368,7 @@ GitVisuals.prototype.animateAllFromAttrToAttr = function(fromSnapshot, toSnapsho
this.visBranchCollection.each(animate);
this.visEdgeCollection.each(animate);
this.visTagCollection.each(animate);
_.each(this.visNodeMap, animate);
Object.values(this.visNodeMap).forEach(animate);
};
/***************************************
@ -392,7 +392,7 @@ GitVisuals.prototype.genSnapshot = function() {
this.fullCalc();
var snapshot = {};
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
snapshot[visNode.get('id')] = visNode.getAttributes();
}, this);
@ -442,7 +442,7 @@ GitVisuals.prototype.fullCalc = function() {
};
GitVisuals.prototype.calcTreeCoords = function() {
// this method can only contain things that dont rely on graphics
// this method can only contain things that don't rely on graphics
if (!this.rootCommit) {
throw new Error('grr, no root commit!');
}
@ -477,7 +477,7 @@ GitVisuals.prototype.getCommitUpstreamBranches = function(commit) {
GitVisuals.prototype.getBlendedHuesForCommit = function(commit) {
var branches = this.upstreamBranchSet[commit.get('id')];
if (!branches) {
throw new Error('that commit doesnt have upstream branches!');
throw new Error('that commit doesn\'t have upstream branches!');
}
return this.blendHuesFromBranchStack(branches);
@ -485,7 +485,7 @@ GitVisuals.prototype.getBlendedHuesForCommit = function(commit) {
GitVisuals.prototype.blendHuesFromBranchStack = function(branchStackArray) {
var hueStrings = [];
_.each(branchStackArray, function(branchWrapper) {
branchStackArray.forEach(function(branchWrapper) {
var fill = branchWrapper.obj.get('visBranch').get('fill');
if (fill.slice(0,3) !== 'hsb') {
@ -525,7 +525,7 @@ GitVisuals.prototype.getCommitUpstreamStatus = function(commit) {
GitVisuals.prototype.calcTagStacks = function() {
var tags = this.gitEngine.getTags();
var map = {};
_.each(tags, function(tag) {
tags.forEach(function(tag) {
var thisId = tag.target.get('id');
map[thisId] = map[thisId] || [];
@ -542,7 +542,7 @@ GitVisuals.prototype.calcTagStacks = function() {
GitVisuals.prototype.calcBranchStacks = function() {
var branches = this.gitEngine.getBranches();
var map = {};
_.each(branches, function(branch) {
branches.forEach(function(branch) {
var thisId = branch.target.get('id');
map[thisId] = map[thisId] || [];
@ -572,7 +572,7 @@ GitVisuals.prototype.calcWidth = function() {
GitVisuals.prototype.maxWidthRecursive = function(commit) {
var childrenTotalWidth = 0;
_.each(commit.get('children'), function(child) {
commit.get('children').forEach(function(child) {
// only include this if we are the "main" parent of
// this child
if (child.isMainParent(commit)) {
@ -601,14 +601,14 @@ GitVisuals.prototype.assignBoundsRecursive = function(commit, min, max) {
// basic box-flex model
var totalFlex = 0;
var children = commit.get('children');
_.each(children, function(child) {
children.forEach(function(child) {
if (child.isMainParent(commit)) {
totalFlex += child.get('visNode').getMaxWidthScaled();
}
}, this);
var prevBound = min;
_.each(children, function(child, index) {
children.forEach(function(child, index) {
if (!child.isMainParent(commit)) {
return;
}
@ -632,7 +632,7 @@ GitVisuals.prototype.calcDepth = function() {
}
var depthIncrement = this.getDepthIncrement(maxDepth);
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
visNode.setDepthBasedOn(depthIncrement, this.getHeaderOffset());
}, this);
};
@ -655,7 +655,7 @@ GitVisuals.prototype.calcDepth = function() {
**************************************/
GitVisuals.prototype.animateNodePositions = function(speed) {
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
visNode.animateUpdatedPosition(speed);
}, this);
};
@ -701,6 +701,25 @@ GitVisuals.prototype.addTagFromEvent = function(tag, collection, index) {
}
};
GitVisuals.prototype.removeTag = function(tag, collection, index) {
var action = function() {
var tagToRemove;
this.visTagCollection.each(function(visTag) {
if(visTag.get('tag') == tag){
tagToRemove = visTag;
}
}, true);
tagToRemove.remove();
this.removeVisTag(tagToRemove);
}.bind(this);
if (!this.gitEngine || !this.gitReady) {
this.defer(action);
} else {
action();
}
};
GitVisuals.prototype.addTag = function(tag) {
var visTag = new VisTag({
tag: tag,
@ -777,7 +796,7 @@ GitVisuals.prototype.calcDepthRecursive = function(commit, depth) {
var children = commit.get('children');
var maxDepth = depth;
_.each(children, function(child) {
children.forEach(function(child) {
var d = this.calcDepthRecursive(child, depth + 1);
maxDepth = Math.max(d, maxDepth);
}, this);
@ -795,7 +814,7 @@ GitVisuals.prototype.canvasResize = function(width, height) {
};
GitVisuals.prototype.genResizeFunc = function() {
this.resizeFunc = _.debounce(
this.resizeFunc = debounce(
function(width, height) {
this.refreshTree();
}.bind(this),
@ -853,7 +872,7 @@ GitVisuals.prototype.zIndexReflow = function() {
};
GitVisuals.prototype.visNodesFront = function() {
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
visNode.toFront();
});
};
@ -892,7 +911,7 @@ GitVisuals.prototype.drawTreeFirstTime = function() {
this.gitReady = true;
this.calcTreeCoords();
_.each(this.visNodeMap, function(visNode) {
Object.values(this.visNodeMap).forEach(function(visNode) {
visNode.genGraphics(this.paper);
}, this);
@ -924,7 +943,7 @@ function blendHueStrings(hueStrings) {
var totalBright = 0;
var length = hueStrings.length;
_.each(hueStrings, function(hueString) {
hueStrings.forEach(function(hueString) {
var exploded = hueString.split('(')[1];
exploded = exploded.split(')')[0];
exploded = exploded.split(',');

View file

@ -1,9 +1,8 @@
var _ = require('underscore');
var Backbone = require('backbone');
var VisBase = Backbone.Model.extend({
removeKeys: function(keys) {
_.each(keys, function(key) {
keys.forEach(function(key) {
if (this.get(key)) {
this.get(key).remove();
}
@ -13,7 +12,7 @@ var VisBase = Backbone.Model.extend({
animateAttrKeys: function(keys, attrObj, speed, easing) {
// either we animate a specific subset of keys or all
// possible things we could animate
keys = _.extend(
keys = Object.assign(
{},
{
include: ['circle', 'arrow', 'rect', 'path', 'text'],
@ -25,15 +24,15 @@ var VisBase = Backbone.Model.extend({
var attr = this.getAttributes();
// safely insert this attribute into all the keys we want
_.each(keys.include, function(key) {
attr[key] = _.extend(
keys.include.forEach(function(key) {
attr[key] = Object.assign(
{},
attr[key],
attrObj
);
});
_.each(keys.exclude, function(key) {
keys.exclude.forEach(function(key) {
delete attr[key];
});
@ -42,4 +41,3 @@ var VisBase = Backbone.Model.extend({
});
exports.VisBase = VisBase;

View file

@ -1,9 +1,8 @@
var _ = require('underscore');
var Backbone = require('backbone');
var VisBase = Backbone.Model.extend({
removeKeys: function(keys) {
_.each(keys, function(key) {
keys.forEach(function(key) {
if (this.get(key)) {
this.get(key).remove();
}
@ -35,14 +34,14 @@ var VisBase = Backbone.Model.extend({
},
setAttrBase: function(keys, attr, instant, speed, easing) {
_.each(keys, function(key) {
keys.forEach(function(key) {
if (instant) {
this.get(key).attr(attr[key]);
} else {
this.get(key).stop();
this.get(key).animate(attr[key], speed, easing);
// some keys dont support animating too, so set those instantly here
_.forEach(this.getNonAnimateKeys(), function(nonAnimateKey) {
// some keys don't support animating too, so set those instantly here
this.getNonAnimateKeys().forEach(function(nonAnimateKey) {
if (attr[key] && attr[key][nonAnimateKey] !== undefined) {
this.get(key).attr(nonAnimateKey, attr[key][nonAnimateKey]);
}
@ -58,7 +57,7 @@ var VisBase = Backbone.Model.extend({
animateAttrKeys: function(keys, attrObj, speed, easing) {
// either we animate a specific subset of keys or all
// possible things we could animate
keys = _.extend(
keys = Object.assign(
{},
{
include: ['circle', 'arrow', 'rect', 'path', 'text'],
@ -70,15 +69,15 @@ var VisBase = Backbone.Model.extend({
var attr = this.getAttributes();
// safely insert this attribute into all the keys we want
_.each(keys.include, function(key) {
attr[key] = _.extend(
keys.include.forEach(function(key) {
attr[key] = Object.assign(
{},
attr[key],
attrObj
);
});
_.each(keys.exclude, function(key) {
keys.exclude.forEach(function(key) {
delete attr[key];
});
@ -87,4 +86,3 @@ var VisBase = Backbone.Model.extend({
});
exports.VisBase = VisBase;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var GRAPHICS = require('../util/constants').GRAPHICS;
@ -167,7 +166,7 @@ var VisBranch = VisBase.extend({
var myArray = this.getBranchStackArray();
var index = -1;
_.each(myArray, function(branch, i) {
myArray.forEach(function(branch, i) {
if (branch.obj == this.get('branch')) {
index = i;
}
@ -279,7 +278,7 @@ var VisBranch = VisBase.extend({
arrowInnerLow,
arrowStartLow
];
_.each(coords, function(pos) {
coords.forEach(function(pos) {
pathStr += 'L' + toStringCoords(pos) + ' ';
}, this);
pathStr += 'z';
@ -309,7 +308,7 @@ var VisBranch = VisBase.extend({
}
var maxWidth = 0;
_.each(this.getBranchStackArray(), function(branch) {
this.getBranchStackArray().forEach(function(branch) {
maxWidth = Math.max(maxWidth, getTextWidth(
branch.obj.get('visBranch')
));
@ -358,6 +357,9 @@ var VisBranch = VisBase.extend({
if (name === 'HEAD' && isHg) {
name = '.';
}
if (name.match(/\bmaster\b/)) {
name = name.replace(/\bmaster\b/, 'main');
}
var after = (selected && !this.getIsInOrigin() && !isRemote) ? '*' : '';
return name + after;
@ -407,11 +409,11 @@ var VisBranch = VisBase.extend({
var textPos = this.getTextPosition();
var name = this.getName();
// when from a reload, we dont need to generate the text
// when from a reload, we don't need to generate the text
var text = paper.text(textPos.x, textPos.y, String(name));
text.attr({
'font-size': 14,
'font-family': 'Monaco, Courier, font-monospace',
'font-family': 'Menlo, Monaco, Consolas, \'Droid Sans Mono\', monospace',
opacity: this.getTextOpacity()
});
this.set('text', text);
@ -432,7 +434,7 @@ var VisBranch = VisBase.extend({
// set CSS
var keys = ['text', 'rect', 'arrow'];
_.each(keys, function(key) {
keys.forEach(function(key) {
$(this.get(key).node).css(attr.css);
}, this);
@ -451,7 +453,7 @@ var VisBranch = VisBase.extend({
this.get('arrow')
];
_.each(objs, function(rObj) {
objs.forEach(function(rObj) {
rObj.click(this.onClick.bind(this));
}, this);
},
@ -577,4 +579,3 @@ var VisBranchCollection = Backbone.Collection.extend({
exports.VisBranchCollection = VisBranchCollection;
exports.VisBranch = VisBranch;
exports.randomHueString = randomHueString;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var GRAPHICS = require('../util/constants').GRAPHICS;
@ -15,7 +14,7 @@ var VisEdge = VisBase.extend({
validateAtInit: function() {
var required = ['tail', 'head'];
_.each(required, function(key) {
required.forEach(function(key) {
if (!this.get(key)) {
throw new Error(key + ' is required!');
}

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var GRAPHICS = require('../util/constants').GRAPHICS;
@ -261,33 +260,33 @@ var VisNode = VisBase.extend({
},
setOutgoingEdgesOpacity: function(opacity) {
_.each(this.get('outgoingEdges'), function(edge) {
this.get('outgoingEdges').forEach(function(edge) {
edge.setOpacity(opacity);
});
},
animateOutgoingEdgesToAttr: function(snapShot, speed, easing) {
_.each(this.get('outgoingEdges'), function(edge) {
this.get('outgoingEdges').forEach(function(edge) {
var attr = snapShot[edge.getID()];
edge.animateToAttr(attr);
}, this);
},
animateOutgoingEdges: function(speed, easing) {
_.each(this.get('outgoingEdges'), function(edge) {
this.get('outgoingEdges').forEach(function(edge) {
edge.animateUpdatedPath(speed, easing);
}, this);
},
animateOutgoingEdgesFromSnapshot: function(snapshot, speed, easing) {
_.each(this.get('outgoingEdges'), function(edge) {
this.get('outgoingEdges').forEach(function(edge) {
var attr = snapshot[edge.getID()];
edge.animateToAttr(attr, speed, easing);
}, this);
},
setOutgoingEdgesBirthPosition: function(parentCoords) {
_.each(this.get('outgoingEdges'), function(edge) {
this.get('outgoingEdges').forEach(function(edge) {
var headPos = edge.get('head').getScreenCoords();
var path = edge.genSmoothBezierPathStringFromCoords(parentCoords, headPos);
edge.get('path').stop();
@ -334,7 +333,7 @@ var VisNode = VisBase.extend({
}
var commandStr = 'git checkout ' + this.get('commit').get('id');
var Main = require('../app');
_.each([this.get('circle'), this.get('text')], function(rObj) {
[this.get('circle'), this.get('text')].forEach(function(rObj) {
rObj.click(function() {
Main.getEventBaton().trigger('commandSubmitted', commandStr);
});
@ -347,7 +346,7 @@ var VisNode = VisBase.extend({
// set the opacity on my stuff
var keys = ['circle', 'text'];
_.each(keys, function(key) {
keys.forEach(function(key) {
this.get(key).attr({
opacity: opacity
});
@ -371,7 +370,7 @@ var VisNode = VisBase.extend({
},
removeAllEdges: function() {
_.each(this.get('outgoingEdges'), function(edge) {
this.get('outgoingEdges').forEach(function(edge) {
edge.remove();
}, this);
},
@ -421,7 +420,7 @@ var VisNode = VisBase.extend({
});
// continuation calculation
if ((vx * vx + vy * vy) < 0.1 && Math.abs(y - maxHeight) <= 0.1) {
// dont need to animate anymore, we are on ground
// don't need to animate anymore, we are on ground
return false;
}
// keep animating!
@ -452,7 +451,7 @@ var VisNode = VisBase.extend({
text.attr({
'font-size': this.getFontSize(this.get('id')),
'font-weight': 'bold',
'font-family': 'Monaco, Courier, font-monospace',
'font-family': 'Menlo, Monaco, Consolas, \'Droid Sans Mono\', monospace',
opacity: this.getOpacity()
});

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var GRAPHICS = require('../util/constants').GRAPHICS;
@ -95,7 +94,7 @@ var VisTag = VisBase.extend({
var myArray = this.getTagStackArray();
var index = -1;
_.each(myArray, function(Tag, i) {
myArray.forEach(function(Tag, i) {
if (Tag.obj == this.get('tag')) {
index = i;
}
@ -175,7 +174,7 @@ var VisTag = VisBase.extend({
var textNode = this.get('text').node;
var maxWidth = 0;
_.each(this.getTagStackArray(), function(Tag) {
this.getTagStackArray().forEach(function(Tag) {
maxWidth = Math.max(maxWidth, getTextWidth(
Tag.obj.get('visTag')
));
@ -251,11 +250,11 @@ var VisTag = VisBase.extend({
var textPos = this.getTextPosition();
var name = this.getName();
// when from a reload, we dont need to generate the text
// when from a reload, we don't need to generate the text
var text = paper.text(textPos.x, textPos.y, String(name));
text.attr({
'font-size': 14,
'font-family': 'Monaco, Courier, font-monospace',
'font-family': 'Menlo, Monaco, Consolas, \'Droid Sans Mono\', monospace',
opacity: this.getTextOpacity(),
'text-anchor': 'start'
});
@ -271,7 +270,7 @@ var VisTag = VisBase.extend({
// set CSS
var keys = ['text', 'rect'];
_.each(keys, function(key) {
keys.forEach(function(key) {
$(this.get(key).node).css(attr.css);
}, this);
@ -289,7 +288,7 @@ var VisTag = VisBase.extend({
this.get('text')
];
_.each(objs, function(rObj) {
objs.forEach(function(rObj) {
rObj.click(this.onClick.bind(this));
}, this);
},
@ -405,4 +404,3 @@ var VisTagCollection = Backbone.Collection.extend({
exports.VisTagCollection = VisTagCollection;
exports.VisTag = VisTag;
exports.randomHueString = randomHueString;

View file

@ -1,4 +1,3 @@
var _ = require('underscore');
var Backbone = require('backbone');
var Collections = require('../models/collections');
@ -13,7 +12,7 @@ var Visualization = Backbone.View.extend({
initialize: function(options) {
options = options || {};
this.options = options;
this.customEvents = _.clone(Backbone.Events);
this.customEvents = Object.assign({}, Backbone.Events);
this.containerElement = options.containerElement;
var _this = this;
@ -34,7 +33,7 @@ var Visualization = Backbone.View.extend({
this.paper = paper;
var Main = require('../app');
// if we dont want to receive keyboard input (directly),
// if we don't want to receive keyboard input (directly),
// make a new event baton so git engine steals something that no one
// is broadcasting to
this.eventBaton = (options.noKeyboardInput) ?
@ -69,9 +68,7 @@ var Visualization = Backbone.View.extend({
this.myResize();
$(window).on('resize', function() {
this.myResize();
}.bind(this));
$(window).on('resize', () => this.myResize());
// If the visualization is within a draggable container, we need to update the
// position whenever the container is moved.
@ -104,7 +101,7 @@ var Visualization = Backbone.View.extend({
makeOrigin: function(options) {
// oh god, here we go. We basically do a bizarre form of composition here,
// where this visualization actually contains another one of itself.
this.originVis = new Visualization(_.extend(
this.originVis = new Visualization(Object.assign(
{},
// copy all of our options over, except...
this.options,
@ -258,12 +255,11 @@ var Visualization = Backbone.View.extend({
myResize: function() {
if (!this.paper) { return; }
var smaller = 1;
var el = this.el;
var elSize = el.getBoundingClientRect();
var width = elSize.width - smaller;
var height = elSize.height - smaller;
var width = elSize.width;
var height = elSize.height;
// if we don't have a container, we need to set our
// position absolutely to whatever we are tracking

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,8 @@ exports.levelSequences = {
require('./remote/pull').level,
require('./remote/fakeTeamwork').level,
require('./remote/push').level,
require('./remote/fetchRebase').level
require('./remote/fetchRebase').level,
require('./remote/lockedMaster').level
],
remoteAdvanced: [
require('./remote/pushManyFeatures').level,
@ -59,12 +60,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : 'まずはここから',
'fr_FR': 'Séquence d\'introduction',
'es_AR': 'Secuencia introductoria',
'es_MX': 'Secuencia introductoria',
'es_ES': 'Secuencia introductoria',
'pt_BR': 'Sequência introdutória',
'gl' : 'Secuencia introductoria',
'zh_CN': '基础篇',
'zh_TW': '基礎篇',
'ko' : 'git 기본',
'ru_RU': 'Введение',
'uk' : 'Вступ'
'uk' : 'Вступ',
'vi' : 'Giới thiệu chuỗi luyện tập',
'sl_SI': 'Uvodno Zaporedje',
'pl' : 'Wprowadzenie',
'ta_IN': 'அறிமுக தொடர் வரிசை'
},
about: {
'en_US': 'A nicely paced introduction to the majority of git commands',
@ -72,12 +80,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : 'gitの基本的なコマンド群をほどよいペースで学ぶ',
'fr_FR': 'Une introduction en douceur à la majorité des commandes git',
'es_AR': 'Una breve introducción a la mayoría de los comandos de git',
'es_MX': 'Una breve introducción a la mayoría de los comandos de git',
'es_ES': 'Una breve introducción a la mayoría de los comandos de git',
'pt_BR': 'Uma breve introdução à maioria dos comandos do git',
'gl' : 'Unha breve introducción á maioría dos comandos de git',
'zh_CN': '循序渐进地介绍 Git 主要命令',
'zh_TW': '循序漸進地介紹 git 主要命令',
'ko' : 'git의 주요 명령어를 깔끔하게 알려드립니다',
'ru_RU': 'Хорошо подобранное введение в основные команды git',
'uk' : 'Гарно підібране введення в основні команди git'
'uk' : 'Гарно підібране введення в основні команди git',
'vi' : 'Từng bước làm quen với phần lớn lệnh điều khiển git',
'sl_SI': 'Prijeten uvod v git ukaze',
'pl' : 'Krótkie wprowadzenie do większości poleceń GIT-a',
'ta_IN': 'பெரும்பாலான கிட் கட்டளைகளுக்கு ஒரு நல்ல அறிமுகம்'
}
},
rampup: {
@ -87,12 +102,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : '次のレベルに進もう',
'fr_FR': 'Montée en puissance',
'es_AR': 'Acelerando',
'es_MX': 'Acelerando',
'es_ES': 'Acelerando',
'pt_BR': 'Acelerando',
'gl' : 'Alixeirando',
'zh_CN': '高级篇',
'zh_TW': '進階篇',
'ru_RU': 'Едем дальше',
'uk' : 'Їдемо далі',
'ko' : '다음 단계로'
'ko' : '다음 단계로',
'vi' : 'Tăng tốc',
'sl_SI': 'Prva Stopnička',
'pl' : 'Rozkręcenie',
'ta_IN': 'சற்று அதிகப்படுத்த'
},
about: {
'en_US': 'The next serving of 100% git awesomes-ness. Hope you\'re hungry',
@ -100,12 +122,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : '更にgitの素晴らしさを堪能しよう',
'fr_FR': 'Le prochain excellent plat de pur git. J\'espère que vous êtes affamés',
'es_AR': 'La próxima porción de 100% maravillas git. Espero que estés hambriento',
'es_MX': 'La próxima ración de git. Espero que estés hambriento',
'es_ES': 'La próxima ración de git. Espero que estés hambriento',
'pt_BR': 'A próxima porção de maravilhas do git. Faminto?',
'gl' : 'A próxima porción das marabillas de git. Agardo que estés esfameado',
'zh_CN': '要开始介绍 Git 的超棒特性了,快来吧!',
'zh_TW': '接下來是 git 非常厲害的地方!相信你已經迫不及待了吧!',
'ru_RU': 'Следующая порция абсолютной git-крутотенюшки. Проголодались?',
'uk' : 'Наступна порція абсолютної git-дивини. Сподіваюсь, ви зголодніли',
'ko' : 'git은 아주 멋져요. 왜 멋진지 알려드립니다'
'ko' : 'git은 아주 멋져요. 왜 멋진지 알려드립니다',
'vi' : 'Tận hưởng khẩu phần tuyệt hảo của git. Hi vọng bạn còn đói.',
'sl_SI': 'Naslednja porcija git izjemnosti. Upam, da si lačen',
'pl' : 'Następna porcja GIT-a jest niesamowita. Mam nadzieję, że jesteś głodny',
'ta_IN': 'அடித்தது கிட்டின் 100% அற்புதங்கள். நீங்கள் ஆர்வமாக உள்ளீர்கள் என்று நம்புகிறேன்'
}
},
remote: {
@ -116,25 +145,39 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : 'Push及びPullコマンド -- Gitリモート',
'fr_FR': 'Push & Pull -- dépôts gits distants !',
'es_AR': 'Push & Pull -- Git Remotes!',
'es_MX': 'Push & Pull -- Repositorios remotos en Git (Git Remotes)!',
'es_ES': 'Push y Pull -- Git Remotes!',
'pt_BR': 'Push & Pull -- repositórios remotos no Git!',
'gl' : 'Push & Pull -- Repositorios remotos no Git!',
'zh_CN': 'Push & Pull —— Git 远程仓库!',
'zh_TW': 'Push & Pull -- Git Remotes!',
'ru_RU': 'Push & Pull - удалённые репозитории в Git!',
'uk' : 'Push & Pull -- віддалені репозиторії в Git!',
'ko' : 'Push & Pull -- Git 원격 저장소!'
'ko' : 'Push & Pull -- Git 원격 저장소!',
'vi' : 'Push & Pull -- Tác động git từ xa!',
'sl_SI': 'Push & Pull -- Oddaljeni Git',
'pl' : 'Push & Pull -- Zdalne repozytoria',
'ta_IN': 'Push & Pull -- கிட் Remotes!'
},
about: {
'en_US': 'Time to share your 1\'s and 0\'s kids; coding just got social',
'fr_FR': 'C\'est le temps de partager vos 1 et vos 0 les enfants, le code vient de devenir social.',
'ja' : '自分のコードをより広く公開しましょう',
'de_DE': 'Zeit Eure 1en und 0en zu teilen; Coding mit sozialer Komponente',
'de_DE': 'Zeit eure 1en und 0en zu teilen; Coding mit sozialer Komponente',
'es_AR': 'Hora de compartir sus 1\'s y 0\'s, chicos; programar se volvió social!',
'es_MX': 'Hora de compartir sus 1\'s y 0\'s, chicos; programar se volvió social!',
'es_ES': 'Hora de compartir vuestros 1\'s y 0\'s, chicos; programar se volvió social!',
'pt_BR': 'Hora de compartilhar seus 1\'s e 0\'s, crianças; programar agora é social!',
'gl' : 'Hora de compartilos seus 1\' e 0\'s, rapaces; programar agora é social!',
'zh_CN': '是时候分享你的代码了,让编码变得社交化吧',
'zh_TW': '是時候分享你的程式碼了',
'ru_RU': 'Настало время поделиться своими единичками и нулями. Время коллективного программирования',
'uk' : 'Настав час поділитися своїми нулями та одиничками; соціальне програмування',
'ko' : '내 코드를 공개할 때가 되었습니다. 코드를 공개해봅시다!'
'ko' : '내 코드를 공개할 때가 되었습니다. 코드를 공개해봅시다!',
'vi' : 'Chia sẻ đứa con tinh thần \'0\' và \'1\' của bạn; mã đã đến với cộng đồng',
'sl_SI': 'Čas za deljenje tvojih 1 in 0; kodiranje je pravkar postalo socialno',
'pl' : 'Czas podzielić się swoimi dziećmi 1 i 0; kodowanie właśnie stało się społeczne',
'ta_IN': 'உங்களின் 1\'கள் மற்றும் 0\'களை பகிர்வதற்கான நேரம் குழந்தைகளே; குறியிடுதல் (coding) பொது உடமை ஆக்க பட்டுள்ளது'
}
},
remoteAdvanced: {
@ -145,53 +188,81 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : '"origin"とその先へ -- Gitリモート上級編',
'fr_FR': 'Vers l\'infini et au-delà -- dépôts distants version avancée',
'es_AR': 'Hasta el origin y más allá -- Git Remotes avanzado!',
'es_MX': 'Hasta el origin y más allá -- Git Remotes avanzado!',
'es_ES': 'Hasta el origen y más allá -- Git Remotes avanzado!',
'pt_BR': 'Até a origin e além -- repositórios remotos avançados!',
'gl' : 'Ata á orixe e máis aló -- repositorios remotos avanzados!',
'zh_CN': '关于 origin 和它的周边 —— Git 远程仓库高级操作',
'zh_TW': '關於 origin 和其它 repogit remote 的進階指令',
'ru_RU': 'Через origin к звёздам. Продвинутое использование Git Remotes',
'uk' : 'Через origin до зірок. Прогресивне використання Git Remotes',
'ko' : '"origin"그 너머로 -- 고급 Git 원격 저장소'
'ko' : '"origin"그 너머로 -- 고급 Git 원격 저장소',
'vi' : 'Về với cội nguồn và vươn xa hơn -- nâng cao về các git remote',
'sl_SI': 'Do Origina In Naprej -- Napredni Oddaljeni Git',
'pl' : 'Do źródła i dalej -- zaawansowane zdalne repozytoria',
'ta_IN': 'ஆரம்பம் மற்றும் அதர்க்கு மேல் -- மேம்பட்ட கிட் ரிமோட்டுகள்!'
},
about: {
'en_US': 'And you thought being a benevolent dictator would be fun...',
'fr_FR': 'Et vous pensiez qu\'être un dictateur bienfaisant serait amusant...',
'ja' : '絶えず上級者の仕事は存在する。。。',
'es_AR': 'Y pensabas que ser un dictador benévolo sería divertido...',
'es_MX': 'Y pensabas que ser un dictador benévolo sería divertido...',
'es_ES': 'Y pensabas que ser un dictador benévolo sería divertido...',
'pt_BR': 'E você achava que ser um déspota esclarecido seria mais divertido...',
'gl' : 'E pensabas que ser un dictador benévolo sería divertido...',
'zh_CN': '做一名仁慈的独裁者一定会很有趣……',
'zh_TW': '而且你會覺得做一個仁慈的獨裁者會很有趣...',
'de_DE': 'Git Remotes für Fortgeschrittene',
'ru_RU': 'Весело было быть всесильным мудрым правителем...',
'uk' : 'А ти думав, що бути всесильним диктатором весело...',
'ko' : '자비로운 독재자가 되는게 재밌을 줄 알았겠지만...'
'ko' : '자비로운 독재자가 되는게 재밌을 줄 알았겠지만...',
'vi' : 'Và bạn nghĩ làm một kẻ độc tài nhân từ thì sẽ vui ...',
'sl_SI': 'In ti si mislil, da je biti dobronamerni diktator zabavno ...',
'pl' : 'A myślałeś, że bycie życzliwym dyktatorem byłoby fajne...',
'ta_IN': 'நீங்கள் ஒரு அக்கரை உள்ள சர்வாதிகாரியாக இருப்பது வேடிக்கையாக இருக்கும் என்று நினைத்தீர்களா...'
}
},
move: {
displayName: {
'en_US': 'Moving Work Around',
'de_DE': 'Code Umherschieben',
'de_DE': 'Code umherschieben',
'fr_FR': 'Déplacer le travail',
'es_AR': 'Moviendo el trabajo por ahí',
'es_MX': 'Moviendo el trabajo por ahí',
'es_ES': 'Moviendo el trabajo por ahí',
'pt_BR': 'Movendo trabalho por aí',
'gl' : 'Movendo o traballo por ahí',
'ja' : 'コードの移動',
'ko' : '코드 이리저리 옮기기',
'zh_CN': '移动提交记录',
'zh_TW': '調整提交順序',
'ru_RU': 'Перемещаем труды туда-сюда',
'uk' : 'Переміщуємо роботу туди-сюди'
'uk' : 'Переміщуємо роботу туди-сюди',
'vi' : 'Điều chỉnh vị trí',
'sl_SI': 'Premikanje Dela Naokrog',
'pl' : 'Przenoszenie pracy',
'ta_IN': 'வேலைகளை பகிர்ந்து கொள்வது'
},
about: {
'en_US': 'Get comfortable with modifying the source tree',
'en_US': '"Git" comfortable with modifying the source tree :P',
'de_DE': 'Gewöhn dich daran, den Git-Baum zu verändern',
'fr_FR': 'Soyez alaise de modifier l\'arbre Git',
'fr_FR': 'Soyez à l\'aise pour modifier l\'arbre Git',
'es_AR': 'Ponete cómodo con modificar el directorio fuente',
'es_MX': 'Ponte cómodo al modificar el directorio fuente :P',
'es_ES': 'Ponte cómodo cuando modifiques el directorio fuente',
'pt_BR': 'Fique confortável em modificar a árvore de códigos',
'gl' : 'Ponte cómodo modificando a árbore de git',
'ko' : '작업 트리를 수정하는건 식은죽 먹기지요 이제',
'ja' : '話題のrebaseってどんなものだろうって人にオススメ',
'zh_CN': '自由修改提交树',
'zh_TW': '自由修改提交樹',
'ru_RU': 'Не стесняйтесь менять историю',
'uk' : 'Не соромимось змінювати історію'
'uk' : 'Не соромимось змінювати історію',
'vi' : 'Chỉnh sửa cây lịch sử Git không hề khó',
'sl_SI': 'Spretno "Git" premikanje po drevesu :P',
'pl' : 'GIT dobrze radzi sobie z modyfikacją drzewa źródłowego :P',
'ta_IN': '"கிட்" மூல மரத்தை மாற்றுவதில் சிரந்தது :P'
}
},
mixed: {
@ -201,12 +272,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : '様々なtips',
'fr_FR': 'Un assortiment',
'es_AR': 'Bolsa de gatos',
'es_MX': 'De todo un poco',
'es_ES': 'Un poco de todo',
'pt_BR': 'Sortidos',
'gl' : 'Todo mesturado',
'ko' : '종합선물세트',
'zh_CN': '杂项',
'zh_TW': '活用 git 的指令',
'ru_RU': 'Сборная солянка',
'uk' : 'Всяке'
'uk' : 'Всяке',
'vi' : 'Những trò mèo đáng đồng tiền bát gạo',
'sl_SI': 'Mešana Vreča',
'pl' : 'Po trochu wszystkiego',
'ta_IN': 'ஒரு கலப்பு பை'
},
about: {
'en_US': 'A mixed bag of Git techniques, tricks, and tips',
@ -214,12 +292,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : 'gitを使う上での様々なtipsやテクニックなど',
'fr_FR': 'Un assortiment de techniques et astuces pour utiliser Git',
'es_AR': 'Un rejunte de técnicas, trucos y tips sobre Git',
'es_MX': 'Un recopilatorio de técnicas, trucos y tips sobre Git',
'es_ES': 'Un batiburrillo de técnicas, trucos y sugerencias sobre Git',
'pt_BR': 'Técnicas, truques e dicas sortidas sobre Git',
'gl' : 'Mestura de técnicas, trucos e consellos',
'ko' : 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다',
'zh_CN': 'Git 技术、技巧与贴士大集合',
'zh_TW': 'git 的技術,招數與技巧',
'ru_RU': 'Ассорти из приёмов работы с Git, хитростей и советов',
'uk' : 'Різні прийоми роботи з Git, хитрощі та поради'
'uk' : 'Різні прийоми роботи з Git, хитрощі та поради',
'vi' : 'Các kỹ thuật, bí quyết, và mẹo vặt hữu ích',
'sl_SI': 'Mešana vreča Git tehnik, trikov in nasvetov',
'pl' : 'Po trochu wszystkiego. Wskazówki i triki',
'ta_IN': 'கிட் நுட்பங்கள், தந்திரங்கள் மற்றும் உதவிக்குறிப்புகளின் கலவையான பை'
}
},
advanced: {
@ -227,14 +312,21 @@ var sequenceInfo = exports.sequenceInfo = {
'en_US': 'Advanced Topics',
'de_DE': 'Themen für Fortgeschrittene',
'ja' : '上級トピック',
'fr_FR': 'Sujets Avancés',
'fr_FR': 'Sujets avancés',
'es_AR': 'Temas avanzados',
'es_MX': 'Temas avanzados',
'es_ES': 'Temas avanzados',
'pt_BR': 'Temas avançados',
'gl' : 'Temas avanzados',
'zh_CN': '高级话题',
'zh_TW': '進階主題',
'ru_RU': 'Продвинутый уровень',
'uk' : 'Досвідчений рівень',
'ko' : '고급 문제'
'ko' : '고급 문제',
'vi' : 'Các chủ đề nâng cao',
'sl_SI': 'Napredne Teme',
'pl' : 'Tematy zaawansowane',
'ta_IN': 'மேம்பட்ட தலைப்புகள்'
},
about: {
'en_US': 'For the truly brave!',
@ -242,12 +334,19 @@ var sequenceInfo = exports.sequenceInfo = {
'ja' : '勇気ある人のみ!',
'fr_FR': 'Pour les plus courageux !',
'es_AR': '¡Para los verdaderos valientes!',
'es_MX': '¡Para los verdaderos valientes!',
'es_ES': '¡Para los verdaderos valientes!',
'pt_BR': 'Para os verdadeiros valentes!',
'gl' : '¡Para os verdadeiros valerosos!',
'zh_CN': '只为真正的勇士!',
'zh_TW': '來成為真正的強者吧!',
'ru_RU': 'Если ты смелый, ловкий, умелый потренируйся тут',
'uk' : 'Для хоробрих',
'ko' : '용기있는 도전자를 위해 준비한 문제입니다'
'ko' : '용기있는 도전자를 위해 준비한 문제입니다',
'vi' : 'Mạnh mẽ lên!',
'sl_SI': 'Za resnično pogumne!',
'pl' : 'Dla naprawdę odważnych!',
'ta_IN': 'உண்மையிலேயே தைரியமானவர்களுக்கு!'
}
}
};

View file

@ -7,25 +7,39 @@ exports.level = {
"ja" : "Gitのブランチ",
"ko": "Git에서 브랜치 쓰기",
"es_AR": "Brancheando en Git",
"es_MX": "Creando ramas en Git",
"es_ES": "Creando ramas en Git",
"pt_BR": "Ramos no Git",
"gl" : "Ramas en Git",
"fr_FR": "Gérer les branches avec Git",
"zh_CN": "Git Branch",
"zh_TW": "建立 git branch",
"ru_RU": "Ветвление в Git",
"uk": "Розгалуження в Git"
"uk": "Розгалуження в Git",
"vi": "Rẽ nhánh với Git",
"sl_SI": "Branchanje v Gitu",
"pl" : "Rozgałęzienia w GIT-cie (branch)",
"ta_IN": "கிட் கிளை நிருவாகம்"
},
"hint": {
"en_US": "Make a new branch with \"git branch <branch-name>\" and check it out with \"git checkout <branch-name>\"",
"de_DE": 'Lege mit "git branch <Name>" einen neuen Branch an und checke ihn mit "git checkout <Name> aus',
"de_DE": "Lege mit \"git branch [Branch-Name]\" einen neuen Branch an und checke ihn mit \"git checkout [Branch-Name]\" aus",
"ja" : "ブランチの作成(\"git branch [ブランチ名]\")と、チェックアウト(\"git checkout [ブランチ名]\"",
"es_AR": "Hacé una nueva rama con \"git branch [nombre]\" y cambiá a ella con \"git checkout [nombre]\"",
"es_MX": "Crea una nueva rama con \"git branch [nombre]\" y sitúate en ella con \"git checkout [nombre]\"",
"es_ES": "Crea una nueva rama con \"git branch [nombre]\" y sitúate en ella con \"git checkout [nombre]\"",
"pt_BR": "Crie um novo ramo com \"git branch [nome]\" e mude para ele com \"git checkout [nome]\"",
"gl" : "Crea unha nova rama con \"git branch [nome]\" e cambiate a ela facendo \"git checkout [nome]\"",
"fr_FR": "Faites une nouvelle branche avec \"git branch [nom]\" positionnez-vous dans celle-ci avec \"git checkout [nom]\"",
"zh_CN": "用 'git branch <分支名>' 来创建分支,用 'git checkout <分支名>' 来切换到分支",
"zh_TW": "用 'git branch [ branch 名稱]' 來建立 branch用 'git checkout [ branch 名稱]' 切換到該 branch",
"ko": "\"git branch [브랜치명]\"으로 새 브랜치를 만들고, \"git checkout [브랜치명]\"로 그 브랜치로 이동하세요",
"ru_RU": "Создай новую ветку при помощи \"git branch [name]\" и перейди на неё при помощи \"git checkout [name]\"",
"uk": "Створи нову гілку за допомогою \"git branch [ім’я]\" й перейди на неї за допомогою \"git checkout [ім’я]\""
"uk": "Створи нову гілку за допомогою \"git branch [ім’я]\" й перейди на неї за допомогою \"git checkout [ім’я]\"",
"vi": "Tạo một nhánh mới với lệnh \"git branch <ten-nhanh>\" và chuyển sang đó với lệnh \"git checkout <ten-nhanh>\"",
"sl_SI": "Naredi nov branch z \"git branch [ime-brancha]\" in ga checkoutaj z \"git checkout [ime-brancha]\"",
"pl" : "Utwórz nowy branch za pomocą \"git branch <branch-name>\" i sprawdź ją za pomocą \"git checkout <branch-name>\"",
"ta_IN": "இப்போது \"git branch <branch-name>\" கட்டளையை கொண்டு புதிய கிளை ஒன்றை உருவாக்குக பின் \"git checkout <branch-name>\" கொண்டு அந்த கிளைக்கு தாவுக"
},
"disabledMap": {
"git revert": true
@ -57,10 +71,10 @@ exports.level = {
"beforeMarkdowns": [
"Let's see what branches look like in practice.",
"",
"Here we will create a new branch named `newImage`"
"Here we will create a new branch named `newImage`."
],
"afterMarkdowns": [
"There, that's all there is to branching! The branch `newImage` now refers to commit `C1`"
"There, that's all there is to branching! The branch `newImage` now refers to commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
@ -70,10 +84,10 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Let's try to put some work on this new branch. Hit the button below"
"Let's try to put some work on this new branch. Hit the button below."
],
"afterMarkdowns": [
"Oh no! The `master` branch moved but the `newImage` branch didn't! That's because we weren't \"on\" the new branch, which is why the asterisk (*) was on `master`"
"Oh no! The `main` branch moved but the `newImage` branch didn't! That's because we weren't \"on\" the new branch, which is why the asterisk (*) was on `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -89,15 +103,26 @@ exports.level = {
"git checkout <name>",
"```",
"",
"This will put us on the new branch before committing our changes"
"This will put us on the new branch before committing our changes."
],
"afterMarkdowns": [
"There we go! Our changes were recorded on the new branch"
"There we go! Our changes were recorded on the new branch."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"*Note: In Git version 2.23, a new command called `git switch` was introduced to eventually replace `git checkout`, ",
"which is somewhat overloaded as a command (it does a bunch of separate things). The lessons here will still use ",
"`checkout` instead of `switch` because most people won't have access to `switch` yet, but support for the new command ",
"works in the app if you want to try it out! You can <a href=\"https://git-scm.com/docs/git-switch\" target=\"_blank\">learn more here</a>.* "
]
}
},
{
"type": "ModalAlert",
"options": {
@ -125,7 +150,7 @@ exports.level = {
"",
"Da das Anlegen von Branches keinen Plattenplatz und Speicher verbraucht, liegt es nahe die Arbeit in kleine logische Häppchen aufzuteilen, anstatt mit wenigen großen, monolithischen Branches zu hantieren.",
"",
"Wir werden sehen wie Commits und Branches zusammengehören sobald wir anfangen mit beiden zu arbeiten. Bis hierhin merk dir einfach, dass ein Branch im Prinzip bedeutet \"ich möchte die Arbeit, die in diesem Commit und seinen Vorgängern steckt, sichern\"."
"Wir werden sehen wie Commits und Branches zusammengehören, sobald wir anfangen mit beiden zu arbeiten. Bis hierhin merk dir einfach, dass ein Branch im Prinzip bedeutet \"ich möchte die Arbeit, die in diesem Commit und seinen Vorgängern steckt, sichern\"."
]
}
},
@ -151,7 +176,7 @@ exports.level = {
"Lass uns mal ein wenig auf dem neuen Branch arbeiten. Machen wir einen Commit:"
],
"afterMarkdowns": [
"Oi! Der Branch `master` hat sich verändert, aber der Branch `issue` nicht. Das liegt daran, dass wir nicht \"auf\" dem neuen Branch waren, weshalb das Sternchen `*` auch hinter `master` steht."
"Oi! Der Branch `main` hat sich verändert, aber der Branch `issue` nicht. Das liegt daran, dass wir nicht \"auf\" dem neuen Branch waren, weshalb das Sternchen `*` auch hinter `main` steht."
],
"command": "git commit",
"beforeCommand": "git branch issue"
@ -228,7 +253,7 @@ exports.level = {
"この新しいブランチに何か変更を加えてみましょう。次のボタンを押してください。"
],
"afterMarkdowns": [
"あらら、`newImage`ではなくて`master`ブランチが移動してしまいました。これは、私たちが`newImage`のブランチ上で作業していなかったためです。どのブランチで作業しているかは、アスタリスク(*)がついてるかどうかで分かります。"
"あらら、`newImage`ではなくて`main`ブランチが移動してしまいました。これは、私たちが`newImage`のブランチ上で作業していなかったためです。どのブランチで作業しているかは、アスタリスク(*)がついてるかどうかで分かります。"
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -278,9 +303,9 @@ exports.level = {
"brancheá temprano, y brancheá seguido",
"```",
"",
"Como no hay consumo extra de alamcenamiento ni memoria al hacer varias ramas, es más fácil dividir lógicamente tu trabajo que tener un par de ramas grandes.",
"Como no hay consumo extra de almacenamiento ni memoria al hacer varias ramas, es más fácil dividir lógicamente tu trabajo que tener un par de ramas grandes.",
"",
"Cuando empecemos a mezclar ramas y commits, vamos a ver cómo se combinan estas dos herramientas. Por ahora, en cambio, simplemente recordá que una rama escencialmente dice \"Quiero incluir el trabajo de este commit y todos su ancestros\"."
"Cuando empecemos a mezclar ramas y commits, vamos a ver cómo se combinan estas dos herramientas. Por ahora, en cambio, simplemente recordá que una rama esencialmente dice \"Quiero incluir el trabajo de este commit y todos su ancestros\"."
]
}
},
@ -290,10 +315,10 @@ exports.level = {
"beforeMarkdowns": [
"Veamos cómo se ven las ramas en práctica.",
"",
"Acá vamos a crear una rama nueva llamada `newImage`"
"Acá vamos a crear una rama nueva llamada `newImage`."
],
"afterMarkdowns": [
"Ahí está, ¡eso es todo lo que hay que hacer para branchear! La rama `newImage` ahora referencia al commit `C1`"
"Ahí está, ¡eso es todo lo que hay que hacer para branchear! La rama `newImage` ahora referencia al commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
@ -303,10 +328,10 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Pongamos algo de trabajo en esta nueva rama. Apretá el botón de acá abajo"
"Pongamos algo de trabajo en esta nueva rama. Apretá el botón de acá abajo."
],
"afterMarkdowns": [
"¡Uh, no! ¡La rama `master` avanzó, pero `newImage` no! Eso es porque no estábamos \"en\" la rama nueva, y por eso el asterisco (*) estaba en `master`"
"¡Uh, no! ¡La rama `main` avanzó, pero `newImage` no! Eso es porque no estábamos \"en\" la rama nueva, y por eso el asterisco (*) estaba en `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -322,10 +347,10 @@ exports.level = {
"git checkout [name]",
"```",
"",
"Esto va a situarnos en esa rama antes de commitear nuestros cambios"
"Esto va a situarnos en esa rama antes de commitear nuestros cambios."
],
"afterMarkdowns": [
"¡Ahí estamos! Nuestros cambios se registraron en nuestra nueva rama"
"¡Ahí estamos! Nuestros cambios se registraron en nuestra nueva rama."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
@ -336,7 +361,163 @@ exports.level = {
"options": {
"markdowns": [
"¡Ok! Ya estás listo para manejar ramas. Cuando se cierre esta ventana,",
"creá una nueva rama llamada `bugFix` y cambiate a ella"
"creá una nueva rama llamada `bugFix` y cambiate a ella."
]
}
}
]
},
"es_MX": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Ramas en Git",
"",
"Las ramas (branches) en Git son increíblemente livianas. Son sólo referencias a un commit específico - nada más. Por esto es que tantos entusiastas de Git siguen el mantra:",
"",
"```",
"branchea temprano, y branchea seguido",
"```",
"",
"Como no hay consumo extra de almacenamiento ni memoria al hacer varias ramas, es más fácil dividir lógicamente tu trabajo que tener un par de ramas grandes.",
"",
"Cuando empecemos a mezclar ramas y commits, vamos a ver cómo se combinan estas dos herramientas. Por ahora, en cambio, simplemente recuerda que una rama esencialmente dice \"Quiero incluir el trabajo de este commit y todos su ancestros\"."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos cómo se ven las ramas en práctica.",
"",
"Acá vamos a crear una rama nueva llamada `newImage`."
],
"afterMarkdowns": [
"Ahí está, ¡eso es todo lo que hay que hacer para branchear! La rama `newImage` ahora referencia al commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Pongamos algo de trabajo en esta nueva rama. Aprieta el botón que se encuentra debajo."
],
"afterMarkdowns": [
"¡Uh, no! ¡La rama `main` avanzó, pero `newImage` no! Eso es porque no estábamos \"en\" la rama nueva, y por eso el asterisco (*) estaba en `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Digámosle a git que queremos hacer checkout a esa rama con",
"",
"```",
"git checkout [name]",
"```",
"",
"Esto nos situará en esa rama antes de hacer commit a nuestros cambios."
],
"afterMarkdowns": [
"¡Ahí estamos! Nuestros cambios se registraron en nuestra nueva rama."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Ok! Ya estás listo para manejar ramas. Cuando se cierre esta ventana,",
"crea una nueva rama llamada `bugFix` y cámbiate a ella."
]
}
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Ramas en Git",
"",
"Las ramas (branches) en Git son increíblemente livianas. Son sólo referencias a un commit específico - nada más. Por esto es que tantos entusiastas de Git siguen el mantra:",
"",
"```",
"crea ramas al principio y hazlo también de manera frecuente",
"```",
"",
"Como no hay consumo extra de almacenamiento ni memoria al crear varias ramas, lógicamente es más fácil dividir tu trabajo que trabajar solamente con un par de ramas grandes.",
"",
"Cuando empecemos a mezclar ramas y commits, vamos a ver cómo se combinan estas dos herramientas. Por ahora, en cambio, simplemente recuerda que una rama esencialmente dice \"Quiero incluir el trabajo de este commit y todos su ancestros\"."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos cómo son las ramas en la práctica.",
"",
"Ahora vamos a crear una rama nueva llamada `newImage`."
],
"afterMarkdowns": [
"Ahí está, ¡eso es todo lo que hay que hacer para crear una rama! La rama `newImage` ahora referencia al commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Pongamos algo de trabajo en esta nueva rama. Aprieta el botón de aquí abajo."
],
"afterMarkdowns": [
"¡Vaya! ¡La rama `main` avanzó, pero `newImage` no! Eso es porque no estábamos \"en\" la rama nueva, y por eso el asterisco (*) estaba en `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Digámosle a git que queremos hacer checkout a esa rama con",
"",
"```",
"git checkout [name]",
"```",
"",
"Esto va a situarnos en esa rama antes de hacer un commit con nuestros cambios."
],
"afterMarkdowns": [
"¡Ahí estamos! Nuestros cambios se registraron en nuestra nueva rama."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Perfecto! Ya estás listo para trabajar con ramas. Cuando se cierre esta ventana,",
"crea una nueva rama llamada `bugFix` y cámbiate a ella."
]
}
}
@ -368,10 +549,10 @@ exports.level = {
"beforeMarkdowns": [
"Vejamos como os ramos funcionam na prática.",
"",
"Aqui vamos criar um novo ramo chamado `newImage`"
"Aqui vamos criar um novo ramo chamado `newImage`."
],
"afterMarkdowns": [
"Veja, é só isso que você tem que fazer para ramificar! O ramo `newImage` agora se refere ao commit `C1`"
"Veja, é só isso que você tem que fazer para ramificar! O ramo `newImage` agora se refere ao commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
@ -381,10 +562,10 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Vamos tentar colocar algum trabalho neste novo ramo. Clique no botão abaixo"
"Vamos tentar colocar algum trabalho neste novo ramo. Clique no botão abaixo."
],
"afterMarkdowns": [
"Ah não! O ramo `master` se moveu mas o `newImage` não! Isso é porque o novo ramo não era o \"ativo\", e é por isso que o asterisco (*) estava no `master`"
"Ah não! O ramo `main` se moveu mas o `newImage` não! Isso é porque o novo ramo não era o \"ativo\", e é por isso que o asterisco (*) estava no `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -400,10 +581,10 @@ exports.level = {
"git checkout [nome]",
"```",
"",
"Isso vai nos situar no ramo antes de commitarmos nossas mudanças"
"Isso vai nos situar no ramo antes de commitarmos nossas mudanças."
],
"afterMarkdowns": [
"Aqui vamos nós! Nossas mudanças foram gravadas no novo ramo"
"Aqui vamos nós! Nossas mudanças foram gravadas no novo ramo."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
@ -414,7 +595,89 @@ exports.level = {
"options": {
"markdowns": [
"Ok! Vocês estão todos prontos para ramificar. Assim que esta janela fechar,",
"crie um novo ramo chamado `bugFix` e mude para esse ramo"
"crie um novo ramo chamado `bugFix` e mude para esse ramo."
]
}
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Ramas en Git",
"",
"As Ramas en Git son tamén increiblemente liviás. Elas sinxelamente son referencias a un mesmo commit específico, e nada máis. É por iso que moitos entusiastas do Git entonan o mantra:",
"",
"```",
"ramifica cedo, ramifica sempre",
"```",
"",
"Debido a non existir sobrecarga de memoria facendo moitas ramas, é máis sinxelo dividir a lóxica do teu traballo en ramas que ter unha enorme.",
"",
"Cando comezamos a mesturar ramas e commits imos ver como eses dous recursos combínanse ben. Por agora lembra que unha rama esencialmente di \"Quero incluír o traballo deste commit e de todos os seus ancestros\"."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Vexamos cómo as ramas funcionan na práctica.",
"",
"Aquí imos crear unha nova rama chamada `newImage`."
],
"afterMarkdowns": [
"Mira, solo tes que poñer eso para crear unha rama! A rama `newImage` agora apunta ó commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Imos intentar colocar algún traballo nesta nova rama. Pincha no botón de abaixo."
],
"afterMarkdowns": [
"¡Bueno home! A rama `main` moveuse pero a rama `newImage` non! Eso é porque a nova rama non era a \"actual\", e é por iso que o asterisco (*) ficaba na rama `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Ímoslle decir a Git que nos queremos mover á rama con:",
"",
"```",
"git checkout [nome]",
"```",
"",
"Esto vainos levar á rama que tiñamos antes de facer os nosos cambios."
],
"afterMarkdowns": [
"¡Imos alá! Os nosos cambios foron grabados na nova rama."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Ok! Estas preparado para facer ramas. Así que podes pechar a ventá,",
"crear unha rama chamada `bugFix` e moverte para esa rama.",
"",
"Inda así, hai un atallo: se ti quixeras crear unha nova ",
"rama e moverte a ela ó mesmo tempo, ti podes escribir simplemente ",
"`git checkout -b [a-tua- rama]`."
]
}
}
@ -446,10 +709,10 @@ exports.level = {
"beforeMarkdowns": [
"Regardons à quoi ressemblent les branches en pratique.",
"",
"Nous allons nous positionner (checkout) dans une nouvelle branche appellée `newImage`"
"Nous allons nous positionner (checkout) dans une nouvelle branche appellée `newImage`."
],
"afterMarkdowns": [
"Et voilà, c'est tout ! La branche `newImage` se réfère désormais au commit `C1`"
"Et voilà, c'est tout ! La branche `newImage` se réfère désormais au commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
@ -462,7 +725,7 @@ exports.level = {
"Travaillons mainenant dans cette branche. Appuyez sur le bouton ci-dessous."
],
"afterMarkdowns": [
"Oh non! La branche `master` a bougé mais pas la branche `newImage` ! C'est parce que nous n'étions pas \"sur\" la nouvelle branche, comme indiqué par l'asterisque (*) sur `master`"
"Oh non! La branche `main` a bougé mais pas la branche `newImage` ! C'est parce que nous n'étions pas \"sur\" la nouvelle branche, comme indiqué par l'astérisque (*) sur `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -478,10 +741,10 @@ exports.level = {
"git checkout [nom]",
"```",
"",
"Cela nous positionne sur la nouvelle branche avant de faire un commit avec nos modifications"
"Cela nous positionne sur la nouvelle branche avant de faire un commit avec nos modifications."
],
"afterMarkdowns": [
"C'est parti ! Nos modifications ont été enregistrées sur la nouvelle branche"
"C'est parti ! Nos modifications ont été enregistrées sur la nouvelle branche."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
@ -492,7 +755,7 @@ exports.level = {
"options": {
"markdowns": [
"Ok! Vous êtes fin prêt pour faire des branches. Après la fermeture de cette fenêtre,",
"faites une nouvelle branche nommée `bugFix` et positionnez-vous sur cette branche"
"faites une nouvelle branche nommée `bugFix` et positionnez-vous sur cette branche."
]
}
}
@ -512,7 +775,7 @@ exports.level = {
"早建分支!多用分支!",
"```",
"",
"这是因为即使创建再多的支也不会造成储存或内存上的开销,并且按逻辑分解工作到不同的分支要比维护那些特别臃肿的分支简单多了。",
"这是因为即使创建再多支也不会造成储存或内存上的开销,并且按逻辑分解工作到不同的分支要比维护那些特别臃肿的分支简单多了。",
"",
"在将分支和提交记录结合起来后,我们会看到两者如何协作。现在只要记住使用分支其实就相当于在说:“我想基于这个提交以及它所有的父提交进行新的工作。”"
]
@ -541,7 +804,7 @@ exports.level = {
],
"command": "git commit",
"afterMarkdowns": [
"哎呀!为什么 `master` 分支前进了,但 `newImage` 分支还待在原地呢?!这是因为我们没有“在”这个新分支上,看到 `master` 分支上的那个星号(*)了吗?这表示当前所在的分支是 `master`。"
"哎呀!为什么 `main` 分支前进了,但 `newImage` 分支还待在原地呢?!这是因为我们没有“在”这个新分支上,看到 `main` 分支上的那个星号(*)了吗?这表示当前所在的分支是 `main`。"
],
"beforeCommand": "git branch newImage"
}
@ -621,7 +884,7 @@ exports.level = {
],
"command": "git commit",
"afterMarkdowns": [
"太奇怪了啦! `master` branch 前進了,但 `newImage` branch 沒有前進!這是因為我們沒有「在」這個新的 branch 上,這也是為什麼星號(*)會在 `master` 上。"
"太奇怪了啦! `main` branch 前進了,但 `newImage` branch 沒有前進!這是因為我們沒有「在」這個新的 branch 上,這也是為什麼星號(*)會在 `main` 上。"
],
"beforeCommand": "git branch newImage"
}
@ -698,7 +961,7 @@ exports.level = {
"이 새로운 브랜치에 약간의 작업을 더해봅시다. 아래 버튼을 눌러주세요"
],
"afterMarkdowns": [
"앗! `master` 브랜치가 움직이고, `newImage` 브랜치는 이동하지 않았네요! 그건 우리가 새 브랜치 위에 있지 않았었기 때문입니다. 별표(*)가 `master`에 있었던 것이죠."
"앗! `main` 브랜치가 움직이고, `newImage` 브랜치는 이동하지 않았네요! 그건 우리가 새 브랜치 위에 있지 않았었기 때문입니다. 별표(*)가 `main`에 있었던 것이죠."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -750,7 +1013,7 @@ exports.level = {
"",
"Так как создание множества веток никак не отражается на памяти или жестком диске, удобнее и проще разбивать свою работу на много маленьких веток, чем хранить все изменения в одной огромной ветке.",
"",
"Чуть позже мы попробуем использовать ветки и коммиты, и вы увидите, как две эти возможности сочетаются. Можно сказать, что созданная ветка хранит изменения текущих коммитов и всех его родителей."
"Чуть позже мы попробуем использовать ветки и коммиты, и вы увидите, как две эти возможности сочетаются. Можно сказать, что созданная ветка хранит изменения текущего коммита и всех его родителей."
]
}
},
@ -760,10 +1023,10 @@ exports.level = {
"beforeMarkdowns": [
"Посмотрим, что такое ветки на практике",
"",
"Создадим здесь новую ветку с именем newImage"
"Создадим здесь новую ветку с именем newImage."
],
"afterMarkdowns": [
"Вот и всё, ребята! Ветка newImage теперь указывает на коммит C1"
"Вот и всё, ребята! Ветка newImage теперь указывает на коммит C1."
],
"command": "git branch newImage",
"beforeCommand": ""
@ -776,7 +1039,7 @@ exports.level = {
"Теперь попробуем сделать некоторые изменения в этой ветке. Для этого нажми кнопку ниже."
],
"afterMarkdowns": [
"О-оу! Ветка master сдвинулась, тогда как ветка newImage - нет! Всё из-за того, что мы не переключились на новую ветку, а остались в старой, о чём говорит звёздочка около ветки master"
"О-оу! Ветка main сдвинулась, тогда как ветка newImage - нет! Всё из-за того, что мы не переключились на новую ветку, а остались в старой, о чём говорит звёздочка около ветки main."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -806,7 +1069,10 @@ exports.level = {
"options": {
"markdowns": [
"Ну что ж, теперь ты готов к работе с ветками. Как только это окно закроется,",
"создай ветку с именем bugFix и переключись на неё"
"создай ветку с именем bugFix и переключись на неё.",
"",
"Кстати вот тебе совет, ты можешь создать новую ветку и переключиться на неё",
"с помощью одной команды: ```git checkout -b [yourbranchname]```.",
]
}
}
@ -854,7 +1120,7 @@ exports.level = {
"Давайте спробуємо додати якусь інформацію до цієї нової гілки. Натисни кнопку внизу."
],
"afterMarkdowns": [
"От халепа! Гілка `master` просунулася вперед, але гілка `newImage` \u2014 ні! Це тому, що ми були не \"на новій гілці\". Через це зірочка (*) була поруч з `master`."
"От халепа! Гілка `main` просунулася вперед, але гілка `newImage` \u2014 ні! Це тому, що ми були не \"на новій гілці\". Через це зірочка (*) була поруч з `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
@ -889,6 +1155,356 @@ exports.level = {
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Nhánh Git",
"",
"Nhánh trong Git cũng nhẹ đến không ngờ. Chúng chỉ đơn giản là các con trỏ đến commit -- không hơn. Đó là lý do các con chiên Git hay niệm chú:",
"",
"```",
"rẽ nhánh sớm, rẽ nhánh thường xuyên",
"```",
"",
"Bởi vì chẳng tốn bao nhiêu bộ nhớ cho việc rẽ nhánh cả, và nó dễ dàng phân chia công việc hơn là có một cái nhánh to tổ chảng.",
"",
"Khi bạn trộn lẫn commit và nhánh, bạn sẽ thấy chúng kết hợp với nhau thế nào. Còn bây giờ, đơn giản hãy nhớ nhánh cơ bản muốn nói \"Tôi muốn thành quả trong commit này và tất cả cha ông của nó\""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Nào hãy xem nhánh trong Git hoạt động thế nào.",
"",
"Giờ chúng ta tạo một nhánh mới tên là `newImage`."
],
"afterMarkdowns": [
"Đó, rẽ nhánh là thế đó! Nhánh `newImage` giờ đã tham chiếu đến commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Nào cùng thử thêm nội dung vào nhánh mới này nào. Hãy bấm nút bên dưới"
],
"afterMarkdowns": [
"Ồ không! Nhánh `main` đã di chuyển nhưng nhánh `newImage` thì không! Đó là do ta không \"nằm trên\" nhánh mới, đó là tại sao dấu hoa thị (*) nằm trên nhánh `main`."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Nào cùng bảo Git chuyển ta sang nhánh khác với lệnh",
"",
"```",
"git checkout <name>",
"```",
"",
"Lệnh này sẽ chuyển ta sang nhánh mới trước khi commit."
],
"afterMarkdowns": [
"Đó! Thay đổi của ta đã được lưu sang nhánh mới"
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Được rồi! Bạn đã sẵn sàng để tập rẽ nhánh rồi. Khi cửa sổ này đóng lại,",
"tạo một nhánh mới tên là `bugFix` và chuyển sang nhánh đó.",
"",
"Tiện thể, có đường tắt đấy: nếu bạn muốn tạo nhánh mới ",
"VÀ đồng thời chuyển sang luôn, bạn chỉ cần ",
"gõ `git checkout -b [yourbranchname]`."
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Branches",
"",
"Tudi branchi v Gitu so izredno majhni. To so preprosto kazalci na določen commit -- nič več. Zato veliko Git navdušencev ponavlja:",
"",
"```",
"branchaj zgodaj in branchaj pogosto",
"```",
"",
"Ker ustvarjanje večih branchev ne porablja dodatnega spomina ali prostora, je lažje logično razdeliti svoje delo kot imeti velike branche.",
"",
"Ko začnemo mešati branche in commite, bomo videli kako se te dve funkcionalnosti dopolnjujeta. Za zdaj si zapomni samo to, da branch ubistvu pomeni \"Hočem vključiti delo tega commita in commite vseh njegovih staršev.\""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poglejmo kako branchi izgledajo v praksi.",
"",
"Tu bomo ustvarili nov branch imenovan `newImage`."
],
"afterMarkdowns": [
"Tako, to je vsa umetnost branchanja! Branch poimenovan `newImage` se sedaj nanaša na commit `C1`."
],
"command": "git branch newImage",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poizkusimo dodati nekaj dela na ta nov branch. Pristisni gumb spodaj."
],
"afterMarkdowns": [
"O ne! `main` branch se je premaknil ampak `newImage` branch se pa ni! To je zato, ker nismo bili \"na\" novem branchu, kot smo lahko videli z označeno zvezdico (*) na `main` branchu."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Povejmo gitu, da želimo checkoutat branch z",
"",
"```",
"git checkout <ime>",
"```",
"",
"To nas bo postavilo na nov branch pred commitanjem sprememb."
],
"afterMarkdowns": [
"Tako je! Naše sprememebe so zabeležene na novem branchu."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ok! Pripravljen si, da začneš branchat. Ko se to okno zapre, ",
"ustvari nov branch z imenom `bugFix` in preklopi na ta branch.",
"",
"Mimogrede, tu je bližnjica: če hočeš narediti nov ",
"branch IN ga hkrati checkoutati, lahko enostavno ",
"natipkaš `git checkout -b [imeTvojegaBrancha]`."
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## GIT Branch",
"",
"Branch w GIT są niezwykle lekkie. Są po prostu wskazówkami dla konkretnego commit-u (zatwierdzenia) i to wszytko. Dlatego tak wielu entuzjastów GIT-a przestrzega Mantry:",
"",
"```",
"twórz branch-e wcześnie i często",
"```",
"",
"Ponieważ tworzenie wielu branch-y nie wiąże się z dodatkowymi kosztami przestrzeni czy też pamięci, dlatego łatwiej jest logicznie podzielić swoją pracę, niż mieć duże, mocne branch-e.",
"",
"Kiedy zaczniemy mieszać branch-e i commit-y, zobaczymy, jak łączą się te dwie funkcje. Na&nbsp;razie jednak pamiętaj, że branch zasadniczo mówi: \"Chcę uwzględnić pracę tego zatwierdzenia oraz wszystkie commit-y nadrzędnych\"."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Zobaczmy, jak wyglądają branch-e (gałęzie) w&nbsp;praktyce.",
"",
"Tutaj utworzymy nowy branch o nazwie `mojBranch`."
],
"afterMarkdowns": [
"To wszystko o rozgałęzieniu! Branch (gałąź) `mojBranch` odnosi się teraz do commit-u (zatwierdzenia) `C1`."
],
"command": "git branch mojBranch",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Spróbujmy trochę popracować nad tą nowym branch-em (gałęzią).\nKliknij przycisk poniżej."
],
"afterMarkdowns": [
"O nie! branch `main` uległ zmianie, a branch `mojBranch` nie! To dlatego, że nie byliśmy \"w\" nowym branch-u (gałęzi) i dlatego gwiazdka (*) była przy `main`"
],
"command": "git commit",
"beforeCommand": "git branch mojBranch"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Powiedzmy GIT-owi, z którym branch-em chcemy pracować",
"",
"```",
"git checkout <nazwa_branch>",
"```",
"",
"Spowoduje to przeniesienie nas do nowego branch-a przed wprowadzeniem zmian."
],
"afterMarkdowns": [
"Gotowe! Nasze zmiany zostały zarejestrowane w nowym branch-u."
],
"command": "git checkout mojBranch; git commit",
"beforeCommand": "git branch mojBranch"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"*Uwaga: w wersji 2.23 GIT-a zostało wprowadzono nowe polecenie o nazwie \n`git switch`, które zastępuje polecenie `git checkout`, ",
"a jest nieco przeciążony poleceniem (robi ono kilka oddzielnych rzeczy). Lekcje tutaj będą nadal używane",
"`checkout` zamiast `switch`, ponieważ większość ludzi nie ma jeszcze dostępu do nowego polecenia `switch`, ale w tej aplikacja obsługuje nowe polecenie, ",
"jeśli chcesz możesz ją wypróbować! Możesz dowiedzieć się więcej o poleceniu <a href=\"https://git-scm.com/docs/git-switch\" target=\"_blank\">tutaj</a>.* "
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ok! Teraz jesteś gotowy do samodzielnego tworzenia gałęzi (branching-u).",
"Po zamknięciu tego okna, stwórz nowy branch o nazwie `bugFix` i przełącz się na ten branch.",
"",
"Przy okazji, oto skrót: jeśli chcesz stworzyć",
"nowy branch ORAZ przełączyć się na niego w tym samym czasie,",
"możesz po prostu wpisać `git checkout -b [nazwa_branch-u]`."
]
}
}
]
},
"ta_IN": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## கிட் கிளைகள்",
"",
"கிட் கிளைகள் மிகவும் இலகுவானவை. அவை ஒரு குரிப்பிட்ட கமிட்டினை சுட்டி காட்டும் ஒரு இணைப்பு குறியீடு மட்டும்தான். இதனால்தான் பல கிட் ஆர்வலர்கள் உச்சரிக்கும் மந்திரம்:",
"",
"```",
"மாற்றம் செய்யும் முன்பே கிளையை உருவாக்குங்ள், அடிக்கடி தேவை என்றால் மேலும் கிளைகளை உருவாக்குங்கள்.",
"```",
"",
"ஏன் என்றால் புதிய கிளைகளை உருவாகுவது சேமிப்புபலுவோ / நினைவக மேலான்மை பலுவோ முற்றிலும் இல்லை, பெரிய பல்வேரு மற்றங்களை கொண்ட பலுமிக்க கிளைகளைக் காட்டிலும் உங்கள் வேலையை தர்க்கமாக சிரு சிரு கிளைகளக பிரிப்பது எளிது.",
"",
"கிளைகள் மற்றும் கமிட்டுகளை கொண்ட கலவை உருவாக்கும் போது இவை இரண்டின் இனக்கத்தினை விவாதிப்போம். தற்ப்போது, கிளை உருவாக்குதல் என்பதை \"இந்த கமிட்டுடன் இதர்க்கு முன் இருந்த அனைத்து கமிட்டுகளையும் தொகுக்க விரும்புகிறேன்.\" என்பதாக கருதலாம்."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"இப்போது நாம் ஒரு கிளை எப்படி இருக்கும் என்பதை பயிற்ச்சி செய்து பார்க்கலாம்.",
"",
"இங்கு `newImage` என்ற பதிய கிளை ஒன்றை உருவாக்குவோம்."
],
"afterMarkdowns": [
"அவ்வலவு தான், `newImage` என்ற புதிய கிளை தயாராகி விட்டது மேலும் அது `C1` என்ற கிட்டை மூலமாக குறிக்கும்படி உள்ளது."
],
"command": "git branch newImage",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"இப்போது அதில் சில மாற்றங்களை இணைப்போம். கீலே உள்ள பித்தேனை அமுக்கவும்."
],
"afterMarkdowns": [
"அடடா! `newImage`க்கு மாறாக `main` கிளை முன்னேறி உள்ளது! ஏன் என்றால் நாம் \"அந்த\" புதிய கிளையில் இல்ல, அதனால்தான் நட்சத்திரக் குறி (*) `main` மேலுள்ளது."
],
"command": "git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"இப்போது நாம் கிட்டை கிளை தாவ சொல்லுவோம்.",
"",
"```",
"git checkout <name>",
"```",
"",
"புதிய மாற்றங்களை கமிட் செய்யும் முன்பு இது நம்மை புதிய கிளைக்கு மாற்றும்."
],
"afterMarkdowns": [
"அவ்வலவுதான்! நமது மாற்றங்கள் புதிய கிளையின் பதிவு செய்ய பட்டுள்ளது."
],
"command": "git checkout newImage; git commit",
"beforeCommand": "git branch newImage"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"*குறிப்பு: கிட் 2.23 முதல், `git switch` என்ற புதிய கட்டளை `git checkout`க்கு மாற்றாக அறிமுகம் செய்ய பட்டுள்ளது, ",
"ஏன் என்றால் அது ஒரே கட்டளையில் அதிகப்படியான வேளைகளை செய்கிறது (சொல்லப்போனால் அது கொத்தாக பல தனிப்பட்ட செயல்களை செய்கின்றது). ",
"இன்னு பலர் `switch` பயன்படுத்த வழி இல்லாததால் இங்குள்ள பாடங்கள் இன்னும் `switch`க்கு பதில் `checkout` பயன்படுத்து கின்றது. ",
"இருப்பினும் இந்த செயலியில் நீங்கள் `switch`ஐ முயற்சிக்க விரும்பினால் செய்யலாம்! <a href=\"https://git-scm.com/docs/git-switch\" target=\"_blank\">மேலும் விவரங்களுக்கு</a>.* "
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"சரி! நீங்கள் இப்போது கிட் கிளை உருவாக்க தயார். இந்த திரை மூடப்பட்டவுடன்,",
"`bugFix` எனும் கிளை உருவாக்கி அந்த கிளைக்கு மாறவும்.",
"",
"சொல்லபோனால், இதற்க்கு ஒரு குறுக்குவழி உள்ளது: ஒரு புதிய கிழையை உருவாக்கி ",
"உடனெ அதற்க்கு மாற, நீங்கள்",
"`git checkout -b [yourbranchname]` என கட்டளையிட்டால் போதும்."
]
}
}
]
}
}
};

View file

@ -3,14 +3,21 @@ exports.level = {
"en_US": "Introduction to Git Commits",
"de_DE": "Einführung in Git Commits",
"es_AR": "Introducción a los commits de Git",
"es_MX": "Introducción a los commits de Git",
"es_ES": "Introducción a los commits de Git",
"pt_BR": "Introdução aos commits no Git",
"gl" : "Introducción ós commits de Git",
"fr_FR": "Introduction aux commits avec Git",
"ja" : "Gitのコミット",
'ko': 'Git 커밋 소개',
'zh_CN': 'Git Commit',
'zh_TW': '介紹 git commit ',
'ru_RU': 'Знакомство с Git Commit ',
'uk': 'Знайомство з комітами в Git'
'uk': 'Знайомство з комітами в Git',
'vi': 'Giới thiệu về Git Commit',
'sl_SI': "Uvod v Git Commit",
'pl' : "Wprowadzenie do zatwierdzeń GIT-a (commit)",
"ta_IN": "கிட் கமிட்கள் ஒரு அறிமுகம்"
},
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C3\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"solutionCommand": "git commit;git commit",
@ -19,14 +26,21 @@ exports.level = {
"en_US": "Just type in 'git commit' twice to finish!",
"de_DE": "Gib einfach zweimal 'git commit' ein um den Level abzuschließen",
"es_AR": "¡Simplemente tipeá 'git commit' dos veces para terminar!",
"es_MX": "¡Simplemente escribe 'git commit' dos veces para terminar!",
"es_ES": "¡Simplemente escribe 'git commit' dos veces para terminar!",
"pt_BR": "Simplesmente digite 'git commit' duas vezes para concluir!",
"gl" : "Simplemente escribe 'git commit' dúas veces para terminar.",
"fr_FR": "Il suffit de saisir 'git commit' deux fois pour réussir !",
"zh_CN": "执行两次 'git commit' 就可以过关了!",
"zh_TW": "輸入兩次 'git commit' 就可以完成!",
"ja" : "'git commit'コマンドを2回打てば完成!",
"ko": "'git commit'이라고 두 번 치세요!",
"ru_RU": "Попробуй дважды выполнить команду 'git commit' ;)",
"uk": "Спробуй двічі виконати команду 'git commit' ;)"
"uk": "Спробуй двічі виконати команду 'git commit' ;)",
'vi': "Đơn giản là cứ gõ 'git commit' 2 lần",
'sl_SI': "Preprosto dvakrat vpiši 'git commit' in zaključi!",
"pl" : "Aby zakończyć, wystarczy dwukrotnie wpisać 'git commit'!",
"ta_IN": "இந்த நிலையை நிரைவு செய்ய 'git commit' என்று இரண்டு முறை தட்டச்சு செய்க!"
},
"disabledMap": {
"git revert": true
@ -39,7 +53,7 @@ exports.level = {
"options": {
"markdowns": [
"## Git Commits",
"A commit in a git repository records a snapshot of all the files in your directory. It's like a giant copy and paste, but even better!",
"A commit in a git repository records a snapshot of all the (tracked) files in your directory. It's like a giant copy and paste, but even better!",
"",
"Git wants to keep commits as lightweight as possible though, so it doesn't just blindly copy the entire directory every time you commit. It can (when possible) compress a commit as a set of changes, or a \"delta\", from one version of the repository to the next.",
"",
@ -55,7 +69,7 @@ exports.level = {
"beforeMarkdowns": [
"Let's see what this looks like in practice. On the right we have a visualization of a (small) git repository. There are two commits right now -- the first initial commit, `C0`, and one commit after that `C1` that might have some meaningful changes.",
"",
"Hit the button below to make a new commit"
"Hit the button below to make a new commit."
],
"afterMarkdowns": [
"There we go! Awesome. We just made changes to the repository and saved them as a commit. The commit we just made has a parent, `C1`, which references which commit it was based off of."
@ -68,7 +82,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"Go ahead and try it out on your own! After this window closes, make two commits to complete the level"
"Go ahead and try it out on your own! After this window closes, make two commits to complete the level."
]
}
}
@ -81,11 +95,11 @@ exports.level = {
"options": {
"markdowns": [
"## Git Commits",
"Ein Commit in ein Git-Repository speichert einen Abbildung aller Dateien in deinem Projektverzeichnis. Es ist wie ein riesiges Kopieren und Einfügen, nur besser.",
"Ein Commit in einem Git-Repository speichert eine Abbildung aller Dateien in deinem Projektverzeichnis. Es ist wie ein riesiges Kopieren und Einfügen, nur besser.",
"",
"Allerdings will Git die Commits so schlank wie möglich halten, also kopiert es nicht einfach stur das ganze Verzeichnis jedes Mal wenn du committest. Es kann (wenn möglich) Commits als Menge von Änderungen zusammenpacken, von einer Version des Repositorys zur nächsten.",
"",
"Außerdem führt Git ein Protokoll darüber welche Commits wann gemacht wurden, und welcher auf welchen folgt. Deshalb werden die Commits hier mit ihrem Vorgänger über sich gezeigt -- wir verwenden Pfeile zur Darstellung der Beziehung. Dieses Protokoll zu haben ist eine tolle Sache für jeden, der an einem Projekt arbeitet.",
"Außerdem führt Git ein Protokoll darüber, welche Commits wann gemacht wurden, und welcher auf welchen folgt. Deshalb werden die Commits hier mit ihrem Vorgänger über sich gezeigt -- wir verwenden Pfeile zur Darstellung der Beziehung. Dieses Protokoll zu haben ist eine tolle Sache für jeden, der an einem Projekt arbeitet.",
"",
"Das war jetzt eine Menge Neues, aber vorerst kannst du dir Commits einfach als Abbildungen des Projekts vorstellen. Commits sind sehr ressourcenschonend, und zwischen ihnen wechseln geht superschnell!"
]
@ -95,7 +109,7 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Mal sehen wie das in der Praxis ist. Rechts sehen wir ein (kleines) Git-Repository. Es gibt akutell zwei Commits -- den initialen, `C0`, und den danach, `C1`, der irgendwelche Änderungen enthält.",
"Mal sehen wie das in der Praxis ist. Rechts sehen wir ein (kleines) Git-Repository. Es gibt aktuell zwei Commits -- den initialen, `C0`, und den danach, `C1`, der irgendwelche Änderungen enthält.",
"",
"Klick die Schaltfläche unten um einen neuen Commit zu erzeugen:"
],
@ -110,7 +124,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"Probier das committen gleich mal aus! Mach zwei Commits um den Level abzuschließen."
"Probier das Committen gleich mal aus! Mach zwei Commits um den Level abzuschließen."
]
}
}
@ -171,7 +185,7 @@ exports.level = {
"## Commits de Git",
"Un commit en un repositorio git registra un snapshot de todos los archivos en tu directorio. Es como un _gran_ copy&paste, ¡pero incluso mejor!",
"",
"Git pretende mantener los commits tan livianos como sea posible, por lo que no copia ciegamente el directorio completo cada vez que commiteás. Puede (cuando es posible) comprimir un commit como un conjunto de cambios (o un _\"delta\"_) entre una versión de tu repositorio y la siguiente.",
"Git pretende mantener los commits tan livianos como sea posible, por lo que no copia ciegamente el directorio completo cada vez que commiteás. Puede (cuando sea posible) comprimir un commit como un conjunto de cambios (o un _\"delta\"_) entre una versión de tu repositorio y la siguiente.",
"",
"Git mantiene, también, un historial de qué commits se hicieron cuándo. Es por eso que la mayoría de los commits tienen commits ancestros arriba suyo -- designamos esto con flechas en nuestra visualización. ¡Mantener el historial es genial para todos los que trabajan en el proyecto!",
"",
@ -185,7 +199,7 @@ exports.level = {
"beforeMarkdowns": [
"Veamos cómo se ve esto en la práctica. A la derecha tenemos una visualización de un (pequeño) repositorio git. Hay dos commits ahora: el commit inicial, `C0`, y un commit que lo sigue, `C1`, que podría tener algunos cambios interesantes.",
"",
"Dale al botón de abajo para hacer un nuevo commit"
"Dale al botón de abajo para hacer un nuevo commit."
],
"afterMarkdowns": [
"¡Ahí va! Increíble. Acabamos de hacer cambios al repositorio y los guardamos como un commit. El commit que acabamos de crear tiene un padre, `C1`, que referencia al commit en que se basó este."
@ -204,6 +218,90 @@ exports.level = {
}
]
},
"es_MX": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Commits de Git",
"Un commit en un repositorio git registra un snapshot de todos los archivos en tu directorio. Es como un _gran_ copy&paste, ¡pero incluso mejor!",
"",
"Git pretende mantener los commits tan livianos como sea posible, por lo que no copia ciegamente el directorio completo cada vez que haces commit. Puede (cuando sea posible) comprimir un commit como un conjunto de cambios (o un _\"delta\"_) entre una versión de tu repositorio y la siguiente.",
"",
"Git mantiene, también, un historial de qué commits se hicieron cuándo. Es por eso que la mayoría de los commits tienen commits ancestros arriba suyo -- designamos esto con flechas en nuestra visualización. ¡Mantener el historial es genial para todos los que trabajan en el proyecto!",
"",
"Hay un montón en lo que ahondar, pero por ahora puedes pensar en los commits como snapshots de tu proyecto. Los commits son muy livianos, y ¡cambiar de uno a otro es terriblemente rápido!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos cómo se ve esto en la práctica. A la derecha tenemos una visualización de un (pequeño) repositorio git. Hay dos commits ahora: el commit inicial, `C0`, y un commit que lo sigue, `C1`, que podría tener algunos cambios interesantes.",
"",
"Dale al botón de abajo para hacer un nuevo commit."
],
"afterMarkdowns": [
"¡Ahí va! Increíble. Acabamos de hacer cambios al repositorio y los guardamos como un commit. El commit que acabamos de crear tiene un padre, `C1`, que referencia al commit en que se basó este."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Vamos, inténtalo ahora! Cuando se cierre esta ventana, haz dos commits para completar el nivel."
]
}
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Commits de Git",
"Un commit en un repositorio git registra un snapshot de todos los archivos en tu directorio. Es como un _gran_ copy&paste, ¡pero incluso mejor!",
"",
"Git pretende mantener los commits tan livianos como sea posible, por lo que no copia ciegamente el directorio completo cada vez que haces un commit. Puede (cuando es posible) comprimir un commit como un conjunto de cambios (o un _\"delta\"_) entre una versión de tu repositorio y la siguiente.",
"",
"Git mantiene, también, un historial de qué commits se hicieron y cuándo. Es por eso que la mayoría de los commits tienen commits ancestros encima -- designamos esto con flechas en nuestra visualización. ¡Mantener el historial es genial para todos los que trabajan en el proyecto!",
"",
"Hay un montón en lo que ahondar, pero por ahora puedes pensar en los commits como snapshots de tu proyecto. Los commits son muy livianos, y ¡cambiar de uno a otro es terriblemente rápido!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos cómo se ve esto en la práctica. A la derecha tenemos una visualización de un (pequeño) repositorio git. Hay dos commits: el commit inicial, `C0`, y un commit que lo sigue, `C1`, que podría tener algunos cambios interesantes.",
"",
"Dale al botón de abajo para crear un nuevo commit."
],
"afterMarkdowns": [
"¡Allá va! Increíble. Acabamos de hacer cambios al repositorio y los guardamos como un commit. El commit que acabamos de crear tiene un padre, `C1`, que referencia al commit en el que se basó este."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Venga, inténtalo ahora! Cuando se cierre esta ventana, crea dos commits para completar el nivel."
]
}
}
]
},
"pt_BR": {
"childViews": [
{
@ -227,7 +325,7 @@ exports.level = {
"beforeMarkdowns": [
"Vejamos o que isso significa na prática. À direita, temos uma visualização de um (pequeno) repositório git. Há dois commits no momento: o commit inicial, `C0`, e um commit que se segue, `C1`, que poderia conter algumas mudanças interessantes.",
"",
"Clique no botão abaixo para fazer um novo commit"
"Clique no botão abaixo para fazer um novo commit."
],
"afterMarkdowns": [
"Aí vamos nós! Incrível. Acabamos de fazer mudanças no repositório e as guardamos como um commit. O commit que acabamos de criar tem um pai, `C1`, que referencia em qual commit ele se baseou."
@ -246,6 +344,48 @@ exports.level = {
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Commits en Git",
"Un commit nun repositorio de git rexistra unha fotografía (snapshot) de tódolos arquivos no seu directorio. É coma un copy&paste xigante, ¡pero todavía mellor!",
"",
"Git quere gardar os commits o máis pequenos posíbel, por iso non copia directamente o directorio completo sempre que fas un commit. El pode (cando é posíbel) comprimir nun commit un conxunto de cambios (ou un _\"delta\"_) entre unha versión do teu respositorio e o seguinte.",
"",
"Git tamén garda un histórico de cando se fixo cada cambio. Por iso a maioría dos commits teñen ancestros enriba deles, e nos indicámolos con frechas na nosa visualización. ¡Manter a historia é óptimo para tódolos que traballan no proxecto!",
"",
"Hai moito que aprender, pero por agora podes pensar que os commits son fotos do teu proxecto. Os commits son liviáns, e cambiar dun para o outro é extremadamente rápido!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Vexamos o que iso significa na práctica. Á dereita, temos unha visualización dun (pequeno) repositorio de git. Hai dous commits por agora: o commit inicial, `C0`, e un commit que lle segue, `C1`, que podería ter algúns cambios interesantes.",
"",
"Pincha no botón de abaixo para facer un novo commit."
],
"afterMarkdowns": [
"¡Alá imos! Mi ma!. Fixemos cambios no repositorio e gardámolos nun commit. O commit que creaches ten un pai, `C1`, que é unha referencia do commit no que se basea."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Alá imos. ¡Inténtao ti agora! Cando se peche a ventá, fai dous commits para completar o nivel."
]
}
}
]
},
"fr_FR": {
"childViews": [
{
@ -273,7 +413,7 @@ exports.level = {
"beforeMarkdowns": [
"Voyons à quoi cela ressemble en pratique. Sur la droite, on peut visualiser un (petit) dépôt git. Il y a pour l'instant deux commits -- le premier commit initial, `C0`, et un commit suivant `C1` qui aurait des changements significatifs.",
"",
"Appuyez sur le bouton ci-dessous pour faire un nouveau commit"
"Appuyez sur le bouton ci-dessous pour faire un nouveau commit."
],
"afterMarkdowns": [
"C'est parti ! Super. Nous venons de faire des modifications sur le dépôt et de sauvegarder celles-ci dans un commit. Ce commit que nous venons de faire a un parent, `C1`, qui référence le commit sur lequel il est basé."
@ -503,6 +643,174 @@ exports.level = {
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Commits",
"Một commit trong một git repository(kho chứa) lưu trữ một ảnh chụp của tất cả các file trong thư mục của bạn. Như kiểu copy và paste cõ bự, thậm chí còn tốt hơn thế!",
"",
"Thế nhưng Git muốn giữ cho các commit nhẹ hết mức có thể, cho nên git không copy tất cả thư mục một cách mù quáng mỗi khi bạn commit. Nó có thể(khi khả dĩ) nén commit như một tập hợp các thay đổi, hay là một \"bản so sánh\", giũa một phiên bản kho chứa git với phiên bản tiếp theo.",
"",
"Đồng thời Git cũng lưu trữ lịch sử commit nào được tạo ra lúc nào. Đó là tại sao hầu hết các commit có commit tổ tiên phía trên nó -- chúng tôi đã hình tượng hóa mối quan hệ này bằng các mũi tên. Trong cộng tác nhóm thì việc gìn giữ lịch sử là rất có ích!",
"",
"Có vẻ là hơi nhiều lý thuyết rồi, bây giờ bạn chỉ cần hiều các commit là các lát cắt của dự án. Các commit rất nhẹ nên việc chuyển qua lại giữa chúng thì nhanh vô cùng!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Thử thực hành chút nào. Ở bên phải chúng ta có mô tả một kho git (nhỏ). Hiện tại đang có 2 commit, một là commit khởi nguyên `C0`, và một commit sau đó `C1` có thể đã có một vài thay đổi.",
"",
"Bấm nút bên dưới để tạo một commit mới"
],
"afterMarkdowns": [
"Đúng rồi! Tuyệt vời. Bạn vừa tạo thay đổi cho kho chứa và lưu vào commit. Cái commit bạn vừa tạo nó có cha, là `C1` đấy, là commit mà nó được tạo ra từ đó."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Nào bây giờ thì thử tự làm bài tập nào! Sau khi đóng cửa sổ này, tạo ra 2 commit để hoàn thành cấp độ"
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Commits",
"Commit v git repozitoriju zabeleži stanje vseh datotek v tvoji mapi. Deluje kot tak velik 'Izreži in Prilepi', vendar še bolje!",
"",
"Git hoče commite ohraniti majhne kot se le da, tako da ne skopira vsakič kar vseh datotek ob commitu. Lahko (kadar je možno) stisne commit le kot množico sprememb oziroma kot \"delto\" sprememb med eno in drugo različico v repozitoriju.",
"",
"Git vodi tudi zgodovino o tem, kdaj je bil kateri commit narejen. Zato ima večina commitov nad seboj svoje prednike -- to je v vizualizaciji predstavljeno s puščicami. Vzdrževanje zgodovine je uporabno za vse, ki delajo na projektu!",
"",
"Veliko je za dojeti na začetku, ampak za zdaj si lahko predstavljaš commite kot posnetek projekta v določenem času. Commiti so zelo majhni in prehajanje med njimi je noro hitro!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poglejmo kako to izgleda v praksi. Na desni imamo vizualizacijo (majhnega) git repozitorija. Trenutno imamo dva commita -- prvi začetni commit, `C0`, in še en commit za tem, `C1`, ki ima lahko pomembne spremembe.",
"",
"Pritisni gumb spodaj, da narediš nov commit."
],
"afterMarkdowns": [
"Tako ja! Super. Pravkar smo naredili spremembe v repozitoriju in jih shranili kot commit. Commit, ki smo ga naredili ima starša, `C1`, ki nam pove iz katerega commita smo izhajali."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Čas je, da poizkusiš sam! Ko se to okno zapre, naredi dva commita, da dokončaš to stopnjo."
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Zatwierdzenia GIT-a (commit)",
"`commit` w repozytorium GIT-a rejestruje migawkę wszystkich (śledzonych) plików w twoim katalogu. To jak gigantyczne kopiowanie i wklejanie, ale jeszcze lepsze!",
"",
"GIT stara się, aby commit-y były tak lekkie, jak to tylko możliwe, więc nie kopiuje na ślepo całego katalogu za każdym razem, gdy zatwierdzasz zmiany. Możesz (jeśli to możliwe) skompresować zatwierdzenie jako zestaw zmian (lub _\"delta\"_) między jedną wersją w repozytorium a następną.",
"",
"GIT przechowuje również historię, kiedy dokonano zatwierdzenia. Dlatego większość commit-ów ma na sobie zmiany przodków -- oznaczamy to strzałkami w naszej wizualizacji. Utrzymanie historii jest świetne dla wszystkich, którzy pracują nad projektem!",
"",
"Jest mnóstwo rzeczy do zagłębienia, ale na razie możesz myśleć o commit-ach jako migawkach projektu. Zatwierdzenia są bardzo lekkie, a przełączanie się między nimi jest niesamowicie szybkie!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Zobaczmy, jak to wygląda w praktyce. Po prawej stronie mamy wizualizację (małego) repozytorium GIT-a. Istnieją dwa zatwierdzenia:\n początkowy commit `C0`, a następnie po nim commit `C1`, które mogą mieć kilka interesujących zmian.",
"",
"Kliknij poniższy przycisk, aby dokonać nowy commit."
],
"afterMarkdowns": [
"Gotowe! Niesamowite. Właśnie wprowadziliśmy zmiany w repozytorium i zapisaliśmy je jako zatwierdzenie (commit). Utworzony przez nas commit ma rodzica `C1`, który odnosi się do commit-a, na który został oparty."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Śmiało i wypróbuj to sam! Po zamknięciu tego okna wykonaj dwa zatwierdzenia (tj. commit-y), aby ukończyć poziom."
]
}
}
]
},
"ta_IN": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## கிட் கமிட்கள்",
"கிட் கமிட் உங்கள் கோப்பகத்தில் உள்ள கண்காணிக்கப்பட்ட (tracked) கோப்புகளை கிட் களஞ்சியத்தில் ஒரு நகலாக பதிவு செய்கின்றது. ஆனால் இது முழு நகல் எடுத்து ஒட்டுவதை விட சிறந்தது!",
"",
"கிட் கமிட்களை முடிந்தவரை இலகுவாக இருக்கும்படி செய்கின்றது, எனவே நீங்கள் ஒவ்வொரு முறை கமிட் செய்யும் போதும் கிட் கோப்பகங்களை கண்மூடித்தனமாக நகலெடுக்காது. அது (முடிந்தால்) கமிட்களை சுருக்கப்பட்ட மாற்றங்களின் தொகுப்பாகவோ, அல்லது களஞ்சியத்தில் ஏற்க்கனவே உள்ள பதிப்பின் \"வேறுபாட்டை\" மட்டும் கண்க்கிட்டோ சேமிக்க செயிகிறது.",
"",
"மேலும் கிட் கமிட்கள் எப்போது செய்யப்படுகிறது என்பதன் வரலாற்றையும் பராமரிக்கிறது. அதனால் தான் பெரும்பான்மையான கமிட்கள் முன்பு பதிவிட்ட கமிட்களை பின் தொடருகின்றன -- நமது வரைபடங்கள் அதனை அம்பு குறியீடுகளாக காட்டு கின்றன. வரலாற்றைப் பராமரிப்பது கணினிதிட்டத்தில் பணிபுரியும் அனைவருக்கும் உதவியாக இருக்கும்!",
"",
"புரிந்து கொள்ள நிறைய இருக்கிறது, ஆனால் இப்போதைக்கு நீங்கள் கமிட்களை திட்டத்தின் பிரதியாக நினைக்கலாம். கமிட்டுகள் மிகவும் இலகுவானவை மேலும் அவற்றுக்கிடையே மாறுவது மிகவும் எளிமையானது!"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"இது நடைமுறையில் எப்படி இருக்கும் என்று பார்ப்போம். இங்கு வலதுபுறத்தில் ஒரு (சிறிய) கிட் களஞ்சியத்தின் காட்சிப்படுத்தல் உள்ளது. இப்போது அதில் இரண்டு கமிட்கள் உள்ளன -- முதல் கமிட், `C0`, மற்றும் மேலும் இரண்டாவதாக `C1` அதில் சில பயண்னுள்ள மாற்றங்கள் இருக்கலாம்.",
"",
"புதிய கமிட் செய்ய கீழே உள்ள பொத்தானை அழுத்தவும்."
],
"afterMarkdowns": [
"அவ்வலவுதான்! அருமை. நாம் களஞ்சியத்தில் மாற்றங்களைச் செய்து கமிட்டாக சேமித்துள்ளோம். இப்போது செய்த கமிட்டிர்க்கு `C1` மூலமாக உள்ளது, அது அதனுடைய மூலத்தை தொடர்ந்து உள்ளது."
],
"command": "git commit",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"இப்போது இந்த திரை மூடிய பிறகு நீங்கள் முயற்சி செய்யுங்கள்!, இந்த நிலையை நிரைவு செய்ய இரண்டு கமிட்டுகள் செய்யுங்கள்."
]
}
}
]
}
}
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
exports.level = {
exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\",\"remoteTrackingBranchID\":null},\"side\":{\"target\":\"C4\",\"id\":\"side\",\"remoteTrackingBranchID\":null},\"bugFix\":{\"target\":\"C7\",\"id\":\"bugFix\",\"remoteTrackingBranchID\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C3\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"tags\":{\"v0\":{\"target\":\"C0\",\"id\":\"v0\",\"type\":\"tag\"},\"v1\":{\"target\":\"C3\",\"id\":\"v1\",\"type\":\"tag\"}},\"HEAD\":{\"target\":\"bugFix\",\"id\":\"HEAD\"}}",
"solutionCommand": "git commit ",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\",\"remoteTrackingBranchID\":null},\"side\":{\"target\":\"C4\",\"id\":\"side\",\"remoteTrackingBranchID\":null},\"bugFix\":{\"target\":\"C6\",\"id\":\"bugFix\",\"remoteTrackingBranchID\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C3\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C5\"],\"id\":\"C6\"}},\"tags\":{\"v0\":{\"target\":\"C0\",\"id\":\"v0\",\"type\":\"tag\"},\"v1\":{\"target\":\"C3\",\"id\":\"v1\",\"type\":\"tag\"}},\"HEAD\":{\"target\":\"bugFix\",\"id\":\"HEAD\"}}",
@ -8,25 +8,33 @@
"de_DE": "Git Describe",
"ja" : "Git Describe",
"es_AR": "Git Describe",
"es_ES": "Git Describe",
"pt_BR": "Git Describe",
"gl" : "Git Describe",
"zh_TW": "git describe",
"zh_CN": "Git Describe",
"ru_RU": "Git describe",
"ko" : "Git describe(묘사)",
"uk" : "Git Describe"
"uk" : "Git Describe",
"vi": "Git Describe(mô tả)",
"sl_SI": "Git Describe"
},
"hint": {
"en_US": "Just commit once on bugFix when you're ready to move on",
"fr_FR": "Faites un commit sur bugFix quand vous êtes pret",
"fr_FR": "Faites un commit sur bugFix quand vous êtes prêt",
"de_DE": "Committe nur einmal auf bugFix, wenn du soweit bist",
"ja" : "次に進む準備が整ったなら、bugFixに対して一回commitしてください",
"es_AR": "Simplemente commiteá una vez en bugFix cuando estés listo para seguir",
"es_ES": "Simplemente crea un commit en la rama bugFix cuando estés listo para seguir",
"pt_BR": "Simplesmente commite uma vez em bugFix quando quiser parar de experimentar",
"gl" : "Simplemente fai commit en bugFix cando estés listo para continuar.",
"zh_TW": "當你要移動的時候,只要在 bugFix 上面 commit 就好了",
"zh_CN": "在 bugFix 上面提交一次就可以了",
"zh_CN": "当你准备好时,在 bugFix 分支上面提交一次就可以了",
"ru_RU": "Когда закончишь, просто сделай commit",
"ko" : "다음으로 넘어가고 싶으면 bugFix를 한번 커밋하면 됩니다.",
"uk" : "Просто зроби один коміт в bugFix коли ти будеш готовий іти далі"
"uk" : "Просто зроби один коміт в bugFix коли ти будеш готовий іти далі",
"vi": "Đơn giản là hãy commit một lẩn ở bugFix là xong rồi",
"sl_SI": "Commitaj enkrat na bugFix, ko boš pripravljen za nadaljevanje."
},
"startDialog": {
"en_US": {
@ -68,7 +76,7 @@
"Let's look at a quick example. For this tree below:"
],
"afterMarkdowns": [
"The command `git describe master` would output:",
"The command `git describe main` would output:",
"",
"`v1_2_gC2`",
"",
@ -102,7 +110,7 @@
"",
"Parce ce que les tags sont de très bonnes références dans le code, git à une commande pour *décrire* (describe) la différence entre le commit et le tag le plus récent. Cette commande s'appelle `git describe` !",
"",
"Git describe peut vous aider lorsque vous vous êtes beaucoup déplacé ; cela peut arriver après un git bisect (chercher l'apparition d'un bug) ou lorsque vous revenez de vacances après 3 semaines sur l'ordinateur d'un collègue."
"Git describe peut vous aider lorsque vous vous êtes beaucoup déplacé; cela peut arriver après un git bisect (chercher l'apparition d'un bug) ou lorsque vous revenez de vacances après 3 semaines sur l'ordinateur d'un collègue."
]
}
},
@ -114,7 +122,7 @@
"",
"`git describe <ref>`",
"",
"où `<ref>` est un n'importe quelle chose que git peut résoudre en un commit. Si vous ne specifiez pas de ref, `HEAD` est pris par défault.",
"où `<ref>` est un n'importe quelle chose que git peut résoudre en un commit. Si vous ne spécifiez pas de ref, `HEAD` est pris par défaut.",
"",
"Le résultat de la commande ressemble à :",
"",
@ -128,10 +136,10 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Regardons un petit exemple. Prennons cet arbre :"
"Regardons un petit exemple. Prenons cet arbre :"
],
"afterMarkdowns": [
"La commande`git describe master` donne le résultat :",
"La commande`git describe main` donne le résultat :",
"",
"`v1_2_gC2`",
"",
@ -194,7 +202,7 @@
"讓我們來看一個例子,對於下面的 tree"
],
"afterMarkdowns": [
"`git describe master` 會輸出:",
"`git describe main` 會輸出:",
"",
"`v1_2_gC2`",
"",
@ -259,7 +267,7 @@
"让我们来看一个例子,对于下面的提交树:"
],
"afterMarkdowns": [
"`git describe master` 会输出:",
"`git describe main` 会输出:",
"",
"`v1_2_gC2`",
"",
@ -322,7 +330,7 @@
"Veamos un ejemplo breve. Para este árbol de commits:"
],
"afterMarkdowns": [
"El comando `git describe master` mostraría:",
"El comando `git describe main` mostraría:",
"",
"`v1_2_gC2`",
"",
@ -346,6 +354,69 @@
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Git Describe",
"",
"Como los tags sirven tanto para marcar \"hitos\" en el código, git tiene un comando para *describir* (_describe_) dónde estás relativo al \"hito\" más cercano (digamos, \"tag\"). Y ese comamndo se llama ¡`git describe`!",
"",
"Git describe puede ayudarte a saber dónde estás después de que te hayas movido varios commits hacia adelante o atrás en la historia. Esto puede pasarte después de que termines un git bisect (una búsqueda que te ayuda a debuggear problemas) o cuando te sientas delante de la computadora de un compañero de trabajo que acaba de volver de unas vacaciones."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Git describe tiene la siguiente forma:",
"",
"`git describe <ref>`",
"",
"Donde `<ref>` es cualquier cosa que git puede resolver a un commit. Si no especificas ninguna referencia, git simplemente usa el commit en el que estás parado ahora (`HEAD`).",
"",
"La salida de ese comando se ve así:",
"",
"`<tag>_<numCommits>_g<hash>`",
"",
"Donde `tag` es el tag más cercano en la historia, `numCommits` dice a cuántos commits de ese tag estás, y `<hash>` es el hash del commit que estás describiendo."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos un ejemplo breve. Para este árbol de commits:"
],
"afterMarkdowns": [
"El comando `git describe main` mostraría:",
"",
"`v1_2_gC2`",
"",
"Mientras que `git describe side` debería mostrar:",
"",
"`v2_1_gC4`"
],
"command": "git tag v2 C3",
"beforeCommand": "git commit; go -b side HEAD~1; gc; gc; git tag v1 C0"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Eso es prácticamente todo lo que hay sobre git describe! Prueba con algunas referencias en este nivel para familiarizarte con el comando.",
"",
"Cuando estés listo, crea un commit para terminar el nivel. Te estamos dando una gratis :P"
]
}
}
]
},
"pt_BR": {
"childViews": [
{
@ -385,7 +456,7 @@
"Vejamos um exemplo rápido. Para a árvore abaixo:"
],
"afterMarkdowns": [
"O comando `git describe master` daria a saída:",
"O comando `git describe main` daria a saída:",
"",
"`v1_2_gC2`",
"",
@ -409,6 +480,69 @@
}
]
},
"gl" : {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Git Describe",
"",
"Como as tags fan a función de \"áncora\" no repositorio, Git ten un comando para *describir* ónde podes estar ti en relación á \"áncora\" (tag) máis próxima. Ese comando chámase `git describe`!",
"",
"Git describe pode axudar a recuperar a túa posición despois de mover moitos commits para atrás ou para adiante na historia; esto pode suceder depois de que fagas un git bisect (unha búsqueda para atopar erros) ou cando te sentas no ordenador dun colega que chegou das vacacións."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Git describe lánzase do seguinte xeito:",
"",
"`git describe <ref>`",
"",
"Onde `<ref>` é qualquera cousa que git poida resolver como unha referencia a un commit. Se non especificas a ref, git usará o commit actual no que se esté traballando (`HEAD`).",
"",
"A resposta do comando é algo semellante a esto:",
"",
"`<tag>_<numCommits>_g<hash>`",
"",
"Onde `tag` é a tag anterior máis próxima na historia, `numCommits` é o número de commits de distancia ó tag, e `<hash>` é o hash do commit no que estamos."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Vexamos un exemplo rápido. Para a árbore de abaixo:"
],
"afterMarkdowns": [
"O comando `git describe main` daría a saída:",
"",
"`v1_2_gC2`",
"",
"Mentres que `git describe side` daría:",
"",
"`v2_1_gC4`"
],
"command": "git tag v2 C3",
"beforeCommand": "git commit; go -b side HEAD~1; gc; gc; git tag v1 C0"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Básicamente é iso do que trata git describe! Intenta descubrir algúns locais da árbore para sentir como se comporta o comando.",
"",
"Cando estés listo, fai un commit para que o nivel remate. Esa é a gracia."
]
}
}
]
},
"de_DE": {
"childViews": [
{
@ -417,9 +551,9 @@
"markdowns": [
"### Git Describe",
"",
"Weil Tags so super als \"Anker\" im Repository dienen können bietet Git einen Befehl um zu *beschreiben* wo du dich relativ zum nächsten \"Anker\" (also Tag) befindest. Und der heißt `git describe`.",
"Weil Tags so super als \"Anker\" im Repository dienen können, bietet Git einen Befehl um zu *beschreiben*, wo du dich relativ zum nächsten \"Anker\" (also Tag) befindest. Und der heißt `git describe`.",
"",
"Er hilft dir dabei, dir einen Überblick zu verschaffen nachdem du viele Commits im Log zurück- oder vorgegangen bist; das kann vorkommen nachdem du ein `git bisect` (eine Fehlersuche) abgeschlossen hast oder wenn du dich an den Rechner eines Kollegen setzt, der gerade aus dem Urlaub gekommen ist."
"Er hilft dir dabei, dir einen Überblick zu verschaffen nachdem du viele Commits im Log zurück- oder vorgegangen bist; das kann vorkommen, nachdem du ein `git bisect` (eine Fehlersuche) abgeschlossen hast oder wenn du dich an den Rechner eines Kollegen setzt, der gerade aus dem Urlaub gekommen ist."
]
}
},
@ -431,13 +565,15 @@
"",
"`git describe <Ref-Name>`",
"",
"Dabei ist `<Ref-Name>` jeder beliebige Name, der einem Commit zugeordnet ist (Branch, Tag etc). Wenn du keinen angibst benutzt Git `HEAD`, also den aktuellen Checkout.",
"Dabei ist `<Ref-Name>` jeder beliebige Name, der einem Commit zugeordnet ist (Branch, Tag etc). Wenn du keinen angibst, benutzt Git `HEAD`, also den aktuellen Checkout.",
"",
"Die Befehlsausgabe sieht so aus:",
"",
"`<Tag-Name>_<Anzahl Commits>_g<Hash>`",
"",
"`<Tag-Name>` ist dabei der nächstliegende Tag in den Vorgänger-Commits, `<Anzahl Commits>` zeigt an, wieviele Commits dieses Tag entfernt ist und `<Hash>` ist das SHA des Commits, auf den das Tag zeigt."
"`<Tag-Name>` ist dabei der nächstliegende Tag in den Vorgänger-Commits, `<Anzahl Commits>` zeigt an, wieviele Commits dieses Tag entfernt ist und `<Hash>` ist das SHA des Commits, auf den HEAD zeigt.",
"",
"**Achtung**: `<Anzahl Commits>` und `<Hash>` erscheint nur, wenn HEAD nicht auf ein Tag zeigt. `git describe` verarbeitet standardmäßig nur annotierte Tags. Um nicht annotierte Tags zu sehen, verwende bitte `git describe --tags`."
]
}
},
@ -448,7 +584,7 @@
"Schauen wir uns das schnell an einem Beispiel an. Für den folgenden Baum:"
],
"afterMarkdowns": [
"Der Befehl `git describe master` würde folgendes ausgeben:",
"Der Befehl `git describe main` würde folgendes ausgeben:",
"",
"`v1_2_gC2`",
"",
@ -511,7 +647,7 @@
"軽い例を見てみましょう。この木においての例は以下のようになります:"
],
"afterMarkdowns": [
"コマンド`git describe master`の結果は以下のようになります:",
"コマンド`git describe main`の結果は以下のようになります:",
"",
"`v1_2_gC2`",
"",
@ -543,7 +679,7 @@
"markdowns": [
"### Git Describe",
"",
"Теги являются прекрасными ориентирами в истории изменений, поэтому в git есть команда, которая показывает, как далеко текущее состоянии от ближайшего тега. И эта команда называется `git describe`",
"Теги являются прекрасными ориентирами в истории изменений, поэтому в git есть команда, которая показывает, как далеко текущее состояние от ближайшего тега. И эта команда называется `git describe`",
"",
"Git describe помогает сориентироваться после отката на много коммитов по истории изменений. Такое может случиться, когда вы сделали `git bisect` или если вы недавно вернулись из отпуска =)"
]
@ -574,7 +710,7 @@
"Посмотрим на простой пример. Для дерева, показанного ниже:"
],
"afterMarkdowns": [
"Команда `git describe master` выведет:",
"Команда `git describe main` выведет:",
"",
"`v1_2_gC2`",
"",
@ -637,7 +773,7 @@
"간단한 예제를 확인해 봅시다. 아래의 트리에서:"
],
"afterMarkdowns": [
"`git describe master` 명령은 다음을 출력합니다:",
"`git describe main` 명령은 다음을 출력합니다:",
"",
"`v1_2_gC2`",
"",
@ -700,7 +836,7 @@
"Розгляньмо короткий приклад. Для дерева нижче:"
],
"afterMarkdowns": [
"Команда `git describe master` виведе:",
"Команда `git describe main` виведе:",
"",
"`v1_2_gC2`",
"",
@ -723,6 +859,132 @@
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Mô tả của Git",
"",
"Bởi gì thẻ đóng vai trò như là \"mỏ neo\" trên cây lịch sử rất tốt rồi, git cũng có lệnh để *mô tả* tương quan của bạn dến vị trí \"mỏ neo\" (thẻ) gần nhất. Và đó là `git describe`!",
"",
"`git descripe` có thể giúp bạn định hướng sau khi dịch chuyển qua lại nhiều lần trên cây lịch sử; đặc biệt là sau khi sử dụng `git bisect` (công cụ tìm kiếm lỗi của git) hoặc khi sử dụng máy của đồng nghiệp mới đi nghỉ mát về."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Cú pháp sử dụng Git describe như sau:",
"",
"`git describe <thamchiếu>`",
"",
"Trong đó `<thamchiếu>` là bất kỳ thứ gì mà git có thể dùng để xác định commit. Nếu bạn không chỉ định tham chiếu, git sẽ dùng vị trí hiện tại của bạn (`HEAD`).",
"",
"Đầu ra của câu lệnh sẽ như sau:",
"",
"`<thẻ>_<sốLượngCommit>_g<mãBăm>`",
"",
"Trong đó `<thẻ>` là thẻ tổ tiên gần nhất, `<sốLượngCommit>` là số lượng commit tính từ tham chiếu đến thẻ, và `<mãBăm>` là mã băm của commit được mô tả."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Cùng xem nhanh một ví dụ trên cây lịch sử phía dưới:"
],
"afterMarkdowns": [
"Câu lệnh `git describe main` sẽ cho kết quả:",
"",
"`v1_2_gC2`",
"",
"Trong khi `git describe side` sẽ cho kết quả:",
"",
"`v2_1_gC4`"
],
"command": "git tag v2 C3",
"beforeCommand": "git commit; go -b side HEAD~1; gc; gc; git tag v1 C0"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Từng đó thông tin là khá đủ về git describe! Hãy thử dùng `git describe` trên vài vị trí để hiểu về lệnh này.",
"",
"Một khi bạn đã sẵn sàng thì chỉ cần commit 1 lần là qua bài này. Bài này dễ chơi rồi nhé :P"
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Git Describe",
"",
"Ker tagi služijo kot tako odlična \"sidra\" v kodi, ima git ukaz za *opis* kje si, relativno glede na najbližje \"sidro\" (aka tag). Temu ukazu se reče `git describe`!",
"",
"Git describe se ti lahko pomaga orientirati, če si premikal veliko commitov naprej in nazaj po zgodovini; to se lahko zgodi, če si končal git bisekcijo (iskanje kot debuggiranje) ali če se usedeš za sodelavčev računalnik, ko je ravno prišel z dopusta."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Git describe izgleda takole:",
"",
"`git describe <ref>`",
"",
"Kjer je `<ref>` karkoli kar lahko git prepozna kot commit. Če ne podaš ref-a, git uporabi mesto, kjer si trenutno checkoutan (`HEAD`).",
"",
"Izpis ukaza je sledeč:",
"",
"`<tag>_<numCommits>_g<hash>`",
"",
"Kjer je `tag` najbližji prednik v zgodovini, `numCommits` je število commitov oddaljenosti tag-a in `<hash>` je hash commita, ki ga opisujemo."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poglejmo hiter primer. Za drevo spodaj:"
],
"afterMarkdowns": [
"Bi ukaz `git describe main` izpisal:",
"",
"`v1_2_gC2`",
"",
"Ukaz `git describe side` pa bi vrnil:",
"",
"`v2_1_gC4`"
],
"command": "git tag v2 C3",
"beforeCommand": "git commit; go -b side HEAD~1; gc; gc; git tag v1 C0"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"To je približno vse, kar se tiče git describe-a! Poizkusi za občutek opisati nekaj lokacij v tej stopnji.",
"",
"Ko si pripravljen, samo enkrat commitaj, da zaključiš stopnjo. Tole ti častimo :P"
]
}
}
]
}
}
};

View file

@ -11,33 +11,41 @@ exports.level = {
"git revert": true
},
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C4%27%22%2C%22id%22%3A%22master%22%7D%2C%22debug%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22debug%22%7D%2C%22printf%22%3A%7B%22target%22%3A%22C3%22%2C%22id%22%3A%22printf%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C4%27%22%2C%22id%22%3A%22bugFix%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C4%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git checkout master;git cherry-pick C4",
"solutionCommand": "git rebase -i main --solution-ordering C4; git rebase bugFix main",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"debug\":{\"target\":\"C2\",\"id\":\"debug\"},\"printf\":{\"target\":\"C3\",\"id\":\"printf\"},\"bugFix\":{\"target\":\"C4\",\"id\":\"bugFix\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"}},\"HEAD\":{\"target\":\"bugFix\",\"id\":\"HEAD\"}}",
"name": {
"ko": "딱 한개의 커밋만 가져오기",
"ko": "딱 한 개의 커밋만 가져오기",
"en_US": "Grabbing Just 1 Commit",
"fr_FR": "Choisir seulement 1 commit",
"de_DE": "Einen Commit pflücken",
"es_AR": "Tomando un único commit",
"es_ES": "Tomando un único commit",
"pt_BR": "Pegando um único commit",
"gl" : "Escollendo un único commit",
"ja": "一つのコミットのみを取得",
"zh_CN": "只取一个提交记录",
"zh_TW": "只取一個 commit",
"ru_RU": "Выберем один коммит.",
"uk": "Вибираємо всього один коміт"
"uk": "Вибираємо всього один коміт",
"vi": "Chỉ lấy 1 commit",
"sl_SI": "Izbiranje Samo Enega Commita"
},
"hint": {
"en_US": "Remember, interactive rebase or cherry-pick is your friend here",
"de_DE": "Vergiss nicht: hier kommst du mit interaktivem Rebase oder Cherry-Picking weiter",
"fr_FR": "Souvenez-vous, les rebases interactifs ou cherry-pick sont vos amis ici.",
"es_AR": "Acordate, el rebase interactivo o cherry-pick son tus amigos acá",
"es_ES": "Recuerda, el rebase interactivo y el cherry-pick son tus amigos",
"pt_BR": "Lembre-se, o rebase interativo ou o cherry-pick são seus amigos aqui",
"gl" : "Recorda, o rebase interativo ou cherry-pick é un dos teus colegas aquí",
"ja": "このレベルではインタラクティブモードのrebaseやcherry-pickがクリアのカギです",
"ko": "대화식 리베이스(rebase -i)나 or 체리픽(cherry-pick)을 사용하세요",
"zh_CN": "你有两个朋友cherry-pick 和 rebase -i",
"zh_TW": "記住,使用互動式的 rebase 或者 cherry-pick 會很有幫助",
"ru_RU": "Не забывай, что интерактивный rebase и cherry-pick это твои друзья!",
"uk": "Не забувай, що інтерактивний rebase та cherry-pick -- це твої друзі!"
"uk": "Не забувай, що інтерактивний rebase та cherry-pick -- це твої друзі!",
"vi": "Hãy nhớ 2 anh bạn tương tác rebase và cherry-pick!",
"sl_SI": "Pomni, interaktivni rebase ali cherry-pick sta tu tvoja prijatelja."
},
"startDialog": {
"en_US": {
@ -52,7 +60,7 @@ exports.level = {
"",
"All of these debugging / print statements are in their own commits. Finally I track down the bug, fix it, and rejoice!",
"",
"Only problem is that I now need to get my `bugFix` back into the `master` branch. If I simply fast-forwarded `master`, then `master` would get all my debug statements which is undesirable. There has to be another way..."
"Only problem is that I now need to get my `bugFix` back into the `main` branch. If I simply fast-forwarded `main`, then `main` would get all my debug statements which is undesirable. There has to be another way..."
]
}
},
@ -73,7 +81,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"This is a later level so we will leave it up to you to decide which command you want to use, but in order to complete the level, make sure `master` receives the commit that `bugFix` references."
"This is a later level so we will leave it up to you to decide which command you want to use, but in order to complete the level, make sure `main` receives the commit that `bugFix` references."
]
}
}
@ -91,7 +99,7 @@ exports.level = {
"",
"Tous ces debug se retrouvent dans une branche particulière. Je trouve le bug et le répare, comme toujours !",
"",
"Le seul problème c'est que je ne peux pas faire de merge ou rebase, car tous ces commits de debug seront dans le master. Il doit y avoir une autre façon..."
"Le seul problème c'est que je ne peux pas faire de merge ou rebase, car tous ces commits de debug seront dans le main. Il doit y avoir une autre façon..."
]
}
},
@ -110,7 +118,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"C'est un niveau avancé, donc à vous de choisir quelle commande utiliser, mais pour réussir ce niveau, assurez-vous que `master` reçoive le même commit que `bugFix` référence."
"C'est un niveau avancé, donc à vous de choisir quelle commande utiliser, mais pour réussir ce niveau, assurez-vous que `main` reçoive le même commit que `bugFix` référence."
]
}
}
@ -128,7 +136,7 @@ exports.level = {
"",
"Todas estas cosas de imprimir y debuggear estan en su propia rama. Finalmente encuentro el problema, lo soluciono, ¡y disfruto!",
"",
"El único problema es que ahora necesito llevar mi `bugFix` a la rama `master`. Si simplemente fast-forwardeo `master`, entonces `master` va a tener todos mis agregados de debugging, que es indeseado. Tiene que haber otro modo..."
"El único problema es que ahora necesito llevar mi `bugFix` a la rama `main`. Si simplemente fast-forwardeo `main`, entonces `main` va a tener todos mis agregados de debugging, que es indeseado. Tiene que haber otro modo..."
]
}
},
@ -149,7 +157,46 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"Este es un nivel más avanzado, así que está en vos decidir cuál de los dos comandos querés usar, pero para completar el nivel asegurate de que `master` recibe el commit que `bugFix` referencia."
"Este es un nivel más avanzado, así que está en vos decidir cuál de los dos comandos querés usar, pero para completar el nivel asegurate de que `main` recibe el commit que `bugFix` referencia."
]
}
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Commits localmente stackeados",
"",
"Esta es una escena que suele pasar cuando uno desarrolla: estoy tratando de encontrar un bug bastante escurridizo. Para ayudar en mi tarea de detective, agrego un par de comandos de debug, y algunas sentencias para imprimir el estado de mi sistema.",
"",
"Todas estas cosas de imprimir y debuggear estan en su propia rama. Finalmente encuentro el problema, lo soluciono, ¡y disfruto!",
"",
"El único problema es que ahora necesito llevar mi `bugFix` a la rama `main`. Si simplemente fast-forwardeo `main`, entonces `main` va a tener todos mis agregados de debugging, lo cual no es deseable. Tiene que haber otro modo..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Necesitamos decirle a git que sólo copie uno de los commits. Esto es tal como los niveles anteriores de mover commits por ahí -- podemos usar los mismos comandos:",
"",
"* `git rebase -i`",
"* `git cherry-pick`",
"",
"Para conseguir este resultado."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Este es un nivel más avanzado, así que debes decidir cuál de los dos comandos quieres usar, pero para completar el nivel asegurate de que `main` recibe el commit que `bugFix` referencia."
]
}
}
@ -167,7 +214,7 @@ exports.level = {
"",
"Todos esses comandos de debug e mensagens estão em seus próprios ramos. Finalmente eu encontro o bug, corrijo, e me regozijo!",
"",
"O único problema é que agora eu preciso devolver o meu `bugFix` ao ramo `master`. Se eu simplesmente der um fast-forward no `master`, então o `master` terminará contendo todos os comandos de debug, o que é indesejável. Deve existir alguma outra forma..."
"O único problema é que agora eu preciso devolver o meu `bugFix` ao ramo `main`. Se eu simplesmente der um fast-forward no `main`, então o `main` terminará contendo todos os comandos de debug, o que é indesejável. Deve existir alguma outra forma..."
]
}
},
@ -188,7 +235,46 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"Este é um nível avançado, então vamos deixar para você a decisão de qual comando usar, mas para completar este nível, certifique-se de que o `master` receba o commit referenciado por `bugFix`."
"Este é um nível avançado, então vamos deixar para você a decisão de qual comando usar, mas para completar este nível, certifique-se de que o `main` receba o commit referenciado por `bugFix`."
]
}
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Commits apilados localmente",
"",
"Aquí estamos nunha situación que acontece de cotio con desenvolvedores: Estou intentando atopar un erro, mais é escorredizo. Para axudar ó meu traballo de detective, eu coloco algúns comandos de debug e prints.",
"",
"¡Todos esos comandos de debug e mensaxes están nas súas ramas propias. Finalmente eu atopo o erro, arránxoo e reorganizo!",
"",
"O único problema é que agora eu preciso devolver o meu `bugFix` á rama `main`. Se eu fixera simplemente un fast-forward en `main`, entón o `main` rematará contendo tódolos comandos de debug, o que é indesexable. Debe existir algunha outra forma..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Precisamos decirlle a git que copie só os commits que nos interesa. Esta situación é exatamente a mesma dos niveis anteriores respecto de como mover o traballo -- podemos usar os mesmos comandos:",
"",
"* `git rebase -i`",
"* `git cherry-pick`",
"",
"Para acadar o objetivo."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Este é un nivel avanzado, entón imos deixarche a decisión de qué comando empregar, pero para completar este nivel, asegurate de que a rama `main` colla o commit referenciado por `bugFix`."
]
}
}
@ -202,11 +288,11 @@ exports.level = {
"markdowns": [
"## Lokale Commit-Haufen",
"",
"Folgende Situation habe ich beim Entwickeln des öfteren: ich bin auf der Suche nach einem Bug, aber er ist echt schwer zu finden. Um ihm auf die Spur zu kommen schreibe ich mehrere Debug-Kommandos und print-Befehle in den Code.",
"Folgende Situation habe ich beim Entwickeln des Öfteren: ich bin auf der Suche nach einem Bug, aber er ist echt schwer zu finden. Um ihm auf die Spur zu kommen schreibe ich mehrere Debug-Kommandos und print-Befehle in den Code.",
"",
"Die committe ich auch immer wieder, je weiter die Suche mich trägt; natürlich in einem lokalen Branch. Schließlich finde ich den Bug, fixe ihn und freue mich!",
"",
"Einziges Problem ist, dass ich diesen `bugFix` jetzt zurück in den `master` kriegen muss. Wenn ich einfach den `master` vorspule oder meinen Branch hinein merge, bekäme der `master` auch die ganzen Debug-Befehle, was nicht gewünscht ist. Das muss anders gehen ..."
"Einziges Problem ist, dass ich diesen `bugFix` jetzt zurück in den `main` kriegen muss. Wenn ich einfach den `main` vorspule oder meinen Branch hinein merge, bekäme der `main` auch die ganzen Debug-Befehle, was nicht gewünscht ist. Das muss anders gehen ..."
]
}
},
@ -226,7 +312,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"Da dies ein späterer Level ist überlasse ich es dir zu entscheiden, welchen Befehl du benutzen willst. Aber um da Level zu schaffen musst du irgendwie sicherstellen, dass `master` den Commit bekommt, auf den `bugFix` zeigt."
"Da dies ein späterer Level ist überlasse ich es dir zu entscheiden, welchen Befehl du benutzen willst. Aber um das Level zu schaffen musst du irgendwie sicherstellen, dass `main` den Commit bekommt, auf den `bugFix` zeigt."
]
}
}
@ -245,7 +331,7 @@ exports.level = {
"",
"これらのデバッグ用のコードはバグ修正用のブランチにコミットされています。そしてついにバグの原因を突き止めて、修正した!やった!",
"",
"あとは`bugFix`ブランチを`master`ブランチに統合できればOK。そこで単純に`master`をfast-forwardすればよいかというと、それでは`master`ブランチの中にデバッグ用のコードも混入してしまいます。"
"あとは`bugFix`ブランチを`main`ブランチに統合できればOK。そこで単純に`main`をfast-forwardすればよいかというと、それでは`main`ブランチの中にデバッグ用のコードも混入してしまいます。"
]
}
},
@ -268,7 +354,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"後半の章ですのでどう解決するかをもう自分で考えることができると思います。このレベルをクリアするためには、`bugFix`が持っているコミットを`master`ブランチが受け取る必要がある点には注意してください。"
"後半の章ですのでどう解決するかをもう自分で考えることができると思います。このレベルをクリアするためには、`bugFix`が持っているコミットを`main`ブランチが受け取る必要がある点には注意してください。"
]
}
}
@ -286,7 +372,7 @@ exports.level = {
"",
"这些调试和打印语句都在它们各自的提交记录里。最后我终于找到了造成这个 Bug 的根本原因,解决掉以后觉得沾沾自喜!",
"",
"最后就差把 `bugFix` 分支里的工作合并回 `master` 分支了。你可以选择通过 fast-forward 快速合并到 `master` 分支上,但这样的话 `master` 分支就会包含我这些调试语句了。你肯定不想这样,应该还有更好的方式……"
"最后就差把 `bugFix` 分支里的工作合并回 `main` 分支了。你可以选择通过 fast-forward 快速合并到 `main` 分支上,但这样的话 `main` 分支就会包含我这些调试语句了。你肯定不想这样,应该还有更好的方式……"
]
}
},
@ -307,7 +393,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"由于我们刚刚闯过类似的关卡,所以要不要再尝试一次就看你自己了。但是如果你想试一把的话,确保 `master` 分支能得到 `bugFix` 分支上的相关提交。"
"由于我们刚刚闯过类似的关卡,所以要不要再尝试一次就看你自己了。但是如果你想试一把的话,确保 `main` 分支能得到 `bugFix` 分支上的相关提交。"
]
}
}
@ -325,7 +411,7 @@ exports.level = {
"",
"所有的這些 debug 的指令都只在 `bugFix` 這個 branch 裡面。最後我終於找到這個 bug並且 fix 掉它,接著撒花慶祝一下!",
"",
"現在唯一的問題就是要把我在 `bugFix` branch 裡面所做的修改 merge 回 `master` branch。我可以簡單地透過 fast-forward 來 merge ,但這樣的話 `master` branch 就會包含這些含有 debug 指令的 commit 了。我相信一定有其它方法..."
"現在唯一的問題就是要把我在 `bugFix` branch 裡面所做的修改 merge 回 `main` branch。我可以簡單地透過 fast-forward 來 merge ,但這樣的話 `main` branch 就會包含這些含有 debug 指令的 commit 了。我相信一定有其它方法..."
]
}
},
@ -346,7 +432,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"這一個關卡是比較後面的關卡,你可以隨意決定你要選擇使用哪個指令,但是 `bugFix` 所指向的那個 commit 一定要可以被 `master` branch 包含到。"
"這一個關卡是比較後面的關卡,你可以隨意決定你要選擇使用哪個指令,但是 `bugFix` 所指向的那個 commit 一定要可以被 `main` branch 包含到。"
]
}
}
@ -360,11 +446,11 @@ exports.level = {
"markdowns": [
"## 로컬에 쌓인 커밋들",
"",
"개발중에 종종 이런 상황이 생깁니다: 잘 띄지 않는 버그를 찾아서 해결하려고, 어떤 부분의 문제인지를 찾기 위해 디버그용 코드와 화면에 정보를 프린트하는 코드 몇 줄 넣습니다. ",
"개발 중에 종종 이런 상황이 생깁니다: 눈에 잘 띄지 않는 버그를 찾아서 해결하려고, 어떤 부분의 문제인지를 찾기 위해 디버그용 코드와 화면에 정보를 프린트하는 코드 몇 줄 넣습니다. ",
"",
"디버깅용 코드나 프린트 명령은 그 브랜치에 들어있습니다. 마침내 버그를 찾아서 고쳤고, 원래 작업하는 브랜치에 합치면 됩니다!",
"",
"이제 `bugFix`브랜치의 내용을 `master`에 합쳐 넣으려 하지만, 한 가지 문제가 있습니다. 그냥 간단히 `master`브랜치를 최신 커밋으로 이동시킨다면(fast-forward) 그 불필요한 디버그용 코드들도 함께 들어가 버린다는 문제죠."
"이제 `bugFix`브랜치의 내용을 `main`에 합쳐 넣으려 하지만, 한 가지 문제가 있습니다. 그냥 간단히 `main`브랜치를 최신 커밋으로 이동시킨다면(fast-forward) 그 불필요한 디버그용 코드들도 함께 들어가 버린다는 문제죠."
]
}
},
@ -387,7 +473,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"이번 레벨을 통과하기 위해 어떤 방법을 쓰시든 자유입니다만, `master`브랜치가 `bugFix` 브랜치의 커밋을 일부 가져오게 해주세요."
"이번 레벨을 통과하기 위해 어떤 방법을 쓰시든 자유입니다만, `main`브랜치가 `bugFix` 브랜치의 커밋을 일부 가져오게 해주세요."
]
}
}
@ -403,7 +489,7 @@ exports.level = {
"",
"Каждая отладочная команда (команды) вывода находится в своём коммите. В итоге мы нашли ошибку, исправили её и порадовались!",
"",
"Но проблема в том, что мы хотим добавить в `master` только исправление ошибки из ветки `bugFix`. Если мы воспользуемся простым fast-forward, то в `master` попадут также отладочные команды. Должен быть другой способ..."
"Но проблема в том, что мы хотим добавить в `main` только исправление ошибки из ветки `bugFix`. Если мы воспользуемся простым fast-forward, то в `main` попадут также отладочные команды. Должен быть другой способ..."
]
}
},
@ -424,7 +510,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"В этом уровне тебе решать, какую команду использовать, но чтобы закончить уровень, убедись, что в мастер попал коммит, на который ссылается `bugFix`"
"В этом уровне тебе решать, какую команду использовать, но чтобы закончить уровень, убедись, что в мастер попал коммит, на который ссылается `bugFix`."
]
}
}
@ -442,7 +528,7 @@ exports.level = {
"",
"Всі ці команди для відлагодження та виводу данних знаходяться в своїх власних комітах. Врешті-решт я знаходжу баг, фікшу його та щиро радію!",
"",
"От тільки лишається проблема, що потрібно мій фікс перенести з `bugFix` назад в гілку `master`. Якщо я просто зроблю фастфорвард (fast-forwarded) в `master`, тоді в `master` потраплять всі мої println'и, що є зайвим. Має бути інший шлях..."
"От тільки лишається проблема, що потрібно мій фікс перенести з `bugFix` назад в гілку `main`. Якщо я просто зроблю фастфорвард (fast-forwarded) в `main`, тоді в `main` потраплять всі мої println'и, що є зайвим. Має бути інший шлях..."
]
}
},
@ -463,7 +549,85 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"На цьому рівні тобі вирішувати якими командами користуватися, але щоб пройти цей рівень, впевнись що в `master` потрапить коміт, на який посилається `bugFix`."
"На цьому рівні тобі вирішувати якими командами користуватися, але щоб пройти цей рівень, впевнись що в `main` потрапить коміт, на який посилається `bugFix`."
]
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Commit xếp chồng tại địa phương",
"",
"Có tình huống thế này thường hay xảy ra trong quá trình phát triển: Tôi dang cố dò lỗi nhưng mà nó lại khá là trúc trắc. Để hỗ trợ cho việc này, thêm vào vài dòng lệnh gỡ lỗi và lệnh in.",
"",
"Mấy lệnh gỡ lỗi và in này nằm yên trong commit của chúng. Cuối cùng thì tôi cũng tìm ra lỗi, gỡ xong, ngon rồi!",
"",
"Bây giờ thì lại phải đưa `bugFix` trở về nhánh `main`. Nếu mà đơn giản dùng fast-forwarded lên `main`, thì `main` lại có tất cả các lệnh gỡ lỗi kia(chẳng muốn chút nào). Phải có cách khác chứ nhỉ..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ta cần phải bảo git chỉ sao chép 1 commit thôi. Điều này giống với cấp độ trước về điều chỉnh vị trí -- ta có thể dùng các câu lệnh tương tự:",
"",
"* `git rebase -i`",
"* `git cherry-pick`",
"",
"Để đạt được mục tiêu này."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Bây giờ là cấp độ cao hơn rồi nên bạn hãy tự quyết định nên dùng câu lệnh nào, nhưng để hoàn thành được cấp độ, hãy đàm bảo rằng `main` nhận được commit mà `bugFix` tham chiếu tới."
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Lokalno naloženi commiti",
"",
"Tu je razvijalska situacija, ki se zgodi pogosto: Hočem najti bug, ampak se kar izmika. V pomoč mojemu detektivskemu delu, sem dodal nekaj ukazov za debuggiranje in izpis.",
"",
"Vsi te ukazi za debuggiranje / izpisovanje so v svojih commitih. Končno odkrijem bug, ga popravim in se veselim!",
"",
"Edini problem je, da morem sedaj spraviti moj `bugFix` nazaj v `main` branch. Če uporabim samo fast-forward na `masterju`, potem bi `main` vseboval vse moje debug vrstice, česar si ne želim. Mora obstajati še neka druga pot ..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Gitu moramo povedati naj skopira čez samo en commit. To je podobno stopnjam prej, ko smo premikali delo okoli -- uporabimo lahko iste ukaze:",
"",
"* `git rebase -i`",
"* `git cherry-pick`",
"",
"da dosežemo ta cilj."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Tebi prepuščam, da se odločiš, kateri ukaz boš uporabil, da končaš stopnjo. Poskrbi samo, da `main` dobi commit na katerega kaže `bugFix` referenca."
]
}
}

View file

@ -15,33 +15,41 @@ exports.level = {
]
},
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C3%27%27%22%2C%22id%22%3A%22master%22%7D%2C%22newImage%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22newImage%22%7D%2C%22caption%22%3A%7B%22target%22%3A%22C3%27%27%22%2C%22id%22%3A%22caption%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C2%27%22%7D%2C%22C2%27%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C2%27%27%22%7D%2C%22C2%27%27%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%27%27%27%22%7D%2C%22C3%27%27%22%3A%7B%22parents%22%3A%5B%22C2%27%27%27%22%5D%2C%22id%22%3A%22C3%27%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git rebase -i HEAD~2 --solution-ordering C3,C2;git commit --amend;git rebase -i HEAD~2 --solution-ordering C2'',C3';git rebase caption master",
"solutionCommand": "git rebase -i HEAD~2 --solution-ordering C3,C2;git commit --amend;git rebase -i HEAD~2 --solution-ordering C2'',C3';git rebase caption main",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"newImage\":{\"target\":\"C2\",\"id\":\"newImage\"},\"caption\":{\"target\":\"C3\",\"id\":\"caption\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"caption\",\"id\":\"HEAD\"}}",
"name": {
"ko": "커밋들 갖고 놀기",
"en_US": "Juggling Commits",
"de_DE": "Jonglieren mit Commits",
"fr_FR": "Jongler avec les Commits",
"fr_FR": "Jongler avec les commits",
"es_AR": "Haciendo malabares con los commits",
"es_ES": "Haciendo malabares con los commits",
"pt_BR": "Malabarismo com commits",
"gl" : "Argallando cos commits",
"ja": "コミットをやりくりする",
"zh_CN": "提交的技巧 #1",
"zh_TW": "commit 的戲法",
"ru_RU": "Жонглируем коммитами",
"uk": "Жонглюємо комітами"
"uk": "Жонглюємо комітами",
"vi": "Tung hứng commit",
"sl_SI": "Žongliranje s Commiti"
},
"hint": {
"en_US": "The first command is git rebase -i HEAD~2",
"de_DE": "Der erste Befehl ist git rebase -i HEAD~2",
"fr_FR": "La première commande est git rebase -i HEAD~2",
"es_AR": "El primer comando es git rebase -i HEAD~2",
"es_ES": "El primer comando es git rebase -i HEAD~2",
"pt_BR": "O primeiro comando é git rebase -i HEAD~2",
"gl" : "O primeiro comando é git rebase -i HEAD~2",
"ja": "最初に打つコマンドはgit rebase -i HEAD~2",
"ko": "첫번째 명령은 git rebase -i HEAD~2 입니다",
"zh_CN": "第一个命令是 `git rebase -i HEAD~2`",
"zh_TW": "第一個命令是 'git rebase -i HEAD~2'",
"ru_RU": "Первой командой должна быть git rebase -i HEAD~2",
"uk": "Перша команда має бути git rebase -i HEAD~2"
"uk": "Перша команда має бути git rebase -i HEAD~2",
"vi": "Lệnh đầu tiên là git rebase -i HEAD~2",
"sl_SI": "Prvi ukaz je git rebase -i HEAD~2."
},
"startDialog": {
"en_US": {
@ -65,14 +73,14 @@ exports.level = {
"We will overcome this difficulty by doing the following:",
"",
"* We will re-order the commits so the one we want to change is on top with `git rebase -i`",
"* We will `commit --amend` to make the slight modification",
"* We will `git commit --amend` to make the slight modification",
"* Then we will re-order the commits back to how they were previously with `git rebase -i`",
"* Finally, we will move master to this updated part of the tree to finish the level (via the method of your choosing)",
"* Finally, we will move main to this updated part of the tree to finish the level (via the method of your choosing)",
"",
"There are many ways to accomplish this overall goal (I see you eye-ing cherry-pick), and we will see more of them later, but for now let's focus on this technique.",
"Lastly, pay attention to the goal state here -- since we move the commits twice, they both get an apostrophe appended. One more apostrophe is added for the commit we amend, which gives us the final form of the tree ",
"",
"That being said, I can compare levels now based on structure and relative apostrophe differences. As long as your tree's `master` branch has the same structure and relative apostrophe differences, I'll give full credit"
"That being said, I can compare levels now based on structure and relative apostrophe differences. As long as your tree's `main` branch has the same structure and relative apostrophe differences, I'll give full credit."
]
}
}
@ -84,9 +92,9 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"## Jongler avec les Commits",
"## Jongler avec les commits",
"",
"Voici une autre situation fréquente. Vous avez certains changements (`newImage`) et un autre groupe de changements (`caption`) qui sont reliés, ils sont donc empilés l'un sur l'autre dans votre dépôt Git (i.e. un après l'autre).",
"Voici une autre situation fréquente. Vous avez certains changements (`newImage`) et un autre groupe de changements (`caption`) qui sont reliés, ils sont donc empilés l'un sur l'autre dans votre dépôt Git (i.e. l'un après l'autre).",
"",
"Là où ça se complique c'est lorsque vous devez faire une petite modification dans un commit antérieur. Dans ce cas, les configurations de `newImage` devront changer un peu, même si ce commit est loin dans notre historique !!"
]
@ -99,15 +107,15 @@ exports.level = {
"Nous allons régler le problème en faisant ceci :",
"",
"* Nous allons réordonner les commits pour que celui que nous voulions changer soit sur le dessus `git rebase -i`",
"* Nous allons utiliser `commit --amend` pour faire les petites modifications",
"* Nous allons utiliser `git commit --amend` pour faire les petites modifications",
"* Nous allons réordonner les commits dans l'ordre original avec `git rebase -i`",
"* Finalement, nous allons déplacer master vers la nouvelle tête de l'arbre (avec la méthode de votre choix)",
"* Finalement, nous allons déplacer main vers la nouvelle tête de l'arbre (avec la méthode de votre choix)",
"",
"Il y a plusieurs façons d'atteindre ce but (cherry-pick semble très tentant), mais nous allons parler de cherry-pick plus tard, pour le moment concentrez-vous sur cette technique.",
"",
"Pour terminer, Faites attention au but -- Dû au fait que nous déplaçons les commits 2 fois, ils se retrouvent les deux avec une apostrophe. Une deuxième apostrophe est ajouté sur le commit que nous modifions, ce qui nous donne l'arbre finale ",
"Pour terminer, Faites attention au but -- Dû au fait que nous déplaçons les commits 2 fois, ils se retrouvent tous les deux avec une apostrophe. Une deuxième apostrophe est ajoutée sur le commit que nous modifions, ce qui nous donne la forme finale de l'arbre.",
"",
"Ceci étant dit, je peux comparer le résultat avec la stucture et les différentes apostophes. Tant que votre arbre master a la même structure et apostrophe le niveau sera considéré réussi."
"Ceci étant dit, je peux comparer le résultat avec la structure et les différentes apostrophes. Tant que votre arbre `main` a la même structure et les différentes apostrophes le niveau sera considéré réussi."
]
}
},
@ -121,7 +129,7 @@ exports.level = {
"markdowns": [
"## Haciendo malabares con los commits",
"",
"Estaes otra situación algo común. Tenés algunos cambios (`newImage`) y otro conjunto de cambios (`caption`) que están relacionados, entonces están apilados en tu repositorio uno encima del otro (es decir, uno después del otro).",
"Esta es otra situación algo común. Tenés algunos cambios (`newImage`) y otro conjunto de cambios (`caption`) que están relacionados, entonces están apilados en tu repositorio uno encima del otro (es decir, uno después del otro).",
"",
"El tema es que a veces tenés que hacer una pequeña modificación a un commit previo. En este caso, la gente de diseño requiere que cambiemos ligeramente las dimensiones de `newImage`, ¡incluso aunque ese commit ya esté atrás en nuestra historia!"
]
@ -134,15 +142,50 @@ exports.level = {
"Superaremos esta dificultad haciendo lo siguiente:",
"",
"* Vamos a reordenar los commits para que el que queremos cambiar quede arriba de todo con `git rebase -i`",
"* Vamos a hacer `commit --amend` para aplicar la ligera modificación",
"* Vamos a hacer `git commit --amend` para aplicar la ligera modificación",
"* Después vamos a reordenar los commits a como estaban con `git rebase -i`",
"* Finalmente, vamos a mover master a esta parte actualizada de nuestor árbol de commits para terminar el nivel (usando el método que prefieras)",
"* Finalmente, vamos a mover main a esta parte actualizada de nuestro árbol de commits para terminar el nivel (usando el método que prefieras)",
"",
"Hay varias maneras de lograr este objetivo en general (ya te veo haciéndole ojitos al cherry-pick), y veremos algunos más después, pero por ahora concentrémonos en esta técnica.",
"",
"Por último, prestá atención al estado final acá -- como movemos los commits dos veces, ambos quedan con un apóstrofe. El commit que corregimos tiene un apóstrofe extra, y así nos queda nuestro árbol final",
"",
"Habiendo dicho eso, puedo comparar los niveles basándome ahora en la estructura y las diferencias relativas de apóstrofes. Mientras que tu rama `master` tenga la misma estructura y diferencias relativas de apóstrofes, te voy a dar el puntaje completo"
"Habiendo dicho eso, puedo comparar los niveles basándome ahora en la estructura y las diferencias relativas de apóstrofes. Mientras que tu rama `main` tenga la misma estructura y diferencias relativas de apóstrofes, te voy a dar el puntaje completo."
]
}
},
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Haciendo malabares con los commits",
"",
"Esta es otra situación algo común. Tienes algunos cambios (`newImage`) y otro conjunto de cambios (`caption`) que están relacionados, entonces están apilados en tu repositorio uno encima del otro (es decir, uno después del otro).",
"",
"El tema es que a veces tienes que hacer una pequeña modificación a un commit previo. En este caso, la gente de diseño requiere que cambiemos ligeramente las dimensiones de `newImage`, ¡incluso aunque ese commit ya se encuentre atrás en nuestra historia!"
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Superaremos esta dificultad haciendo lo siguiente:",
"",
"* Vamos a reordenar los commits para que el que queremos cambiar quede arriba de los demás con `git rebase -i`",
"* Vamos a hacer `git commit --amend` para aplicar la ligera modificación",
"* Después vamos a reordenar los commits a como estaban con `git rebase -i`",
"* Finalmente, vamos a mover main a esta parte actualizada de nuestro árbol de commits para terminar el nivel (usando el método que prefieras)",
"",
"Hay varias maneras de lograr este objetivo en general (ya te veo haciéndole ojitos al cherry-pick), y veremos algunos más después, pero por ahora concentrémonos en esta técnica.",
"",
"Por último, presta atención al estado final -- como movemos los commits dos veces, ambos quedan con un apóstrofe. El commit que corregimos tiene un apóstrofe extra, y así nos queda nuestro árbol final",
"",
"Habiendo dicho eso, puedo comparar los niveles basándome ahora en la estructura y las diferencias relativas de apóstrofes. Mientras que tu rama `main` tenga la misma estructura y diferencias relativas de apóstrofes, te voy a dar el puntaje completo."
]
}
},
@ -171,13 +214,48 @@ exports.level = {
"* Reordenaremos os commits de forma que aquele que desejamos esteja no topo, com `git rebase -i`",
"* Usaremos o comando `git commit --amend` para fazer uma pequena modificação",
"* Vamos, então, reordenar os commits na mesma ordem que estavam anteriormente com `git rebase -i`",
"* Finalmente, moveremos o master para essa parte atualizada da árvore para finalizar o nível (usando o método de sua escolha)",
"* Finalmente, moveremos o main para essa parte atualizada da árvore para finalizar o nível (usando o método de sua escolha)",
"",
"Há muitas formas de alcançar o objetivo final (eu vejo o cherry-pick passando pela sua mente), e veremos mais delas depois, mas por enquanto foquemos nesta técnica.",
"",
"Por último, preste atenção no estado do \"objetivo\" aqui -- como nós movemos os commits duas vezes, ambos ficam com um apóstrofo. Um apóstrofo adicional é colocado no commit que sofreu o \"amend\", o que nos dá a forma final da árvore ",
"",
"Tendo dito isto, posso avaliar a resposta baseado na estrutura e nas diferenças relativas de número de apóstrofos. Desde que o ramo `master` da sua árvore tenha a mesma estrutura, e o número de apóstrofos seja igual a menos de uma constante, darei a você todos os pontos para esta tarefa"
"Tendo dito isto, posso avaliar a resposta baseado na estrutura e nas diferenças relativas de número de apóstrofos. Desde que o ramo `main` da sua árvore tenha a mesma estrutura, e o número de apóstrofos seja igual a menos de uma constante, darei a você todos os pontos para esta tarefa."
]
}
},
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Argallando cos commits",
"",
"Aquí está outra situación que acontece con bastante frecuencia. Estás facendo algúns cambios (`newImage`), separado do resto de cambios (`caption`) que están relacionados, deste xeito están apilados un enriba do outro no teu repositorio.",
"",
"O complicado é que ás veces, poida que precises facer unha pequena nota nun commit máis antigo. Neste caso, a persoa de deseño quere mudar un pouco as dimensións da imaxe introducida en `newImage`, a pesar de que ese commit está máis abaixo no noso histórico!!"
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Superamos este problema facendo o seguinte:",
"",
"* Reordenaremos os commits seleccionando aqueles que desexamos que estén no cambio, con `git rebase -i`",
"* Empregaremos o comando `git commit --amend` para facer unha pequena modificación",
"* Imos, entón, reordear os commits na mesma orde na que estaban anteriormente con `git rebase -i`",
"* Finalmente, moveremos o main para esa parte atualizada da árbore e así finalizar o nivel (usando o método que máis che pete)",
"",
"Hai moitas formas de obter o obxectivo final (eu vexo o cherry-pick pasando pola túa cachola), e verémolo máis adiante, pero agora ímonos centrar nesta técnica.",
"",
"Por último, preste atención no estado do \"objectivo\" aquí -- como movemos os commits dúas veces, ambos teñen o apóstrofo sumado. O apóstrofo engádese polo commit que nos correximos (amend), o cal danos a forma final da árbore.",
"",
"Contado todo esto, a resposta valídase baseándose na estructura e nos diferentes apóstrofes. Cando a rama `main` teña a mesma estructura, e o número de apóstrofos sexa igual, obterás todos os puntos da tarefa."
]
}
},
@ -203,16 +281,16 @@ exports.level = {
"markdowns": [
"Um das zu schaffen gehen wir wie folgt vor:",
"",
"* Wir sortieren die Commits mit `git rebase -i` so um, dass der, den wir ändern wollen, ganz oben liegt.",
"* Wir sortieren die Commits mit `git rebase -i` so um, dass der Commit, den wir ändern wollen, ganz oben liegt.",
"* Wir verändern den Commit mit `git commit --amend`.",
"* Dann sortieren wir die Commit mit einem erneuten `git rebase -i` wieder in die alte Reihenfolge.",
"* Schließlich aktualisieren wir den `master` auf das Ende unseres fertigen Baums, um diesen Level abzuschließen.",
"* Dann sortieren wir die Commits mit einem erneuten `git rebase -i` wieder in die alte Reihenfolge.",
"* Schließlich aktualisieren wir den `main` auf das Ende unseres fertigen Baums, um diesen Level abzuschließen.",
"",
"Es gibt sehr viele Wege um das Endziel dieses Levels zu erreichen (ich sehe, du schielst auf `cherry-pick`) und wir werden uns später noch andere ansehen. Aber für's erste lass uns diese Methode ausprobieren.",
"",
"Beachte den geschilderten Zielzustand. Da wir die Commits zweimal umsortieren bekommen sie jedesmal ein Apostroph hinzugefügt (weil sie jedesmal kopiert werden). Ein weiteres Apostroph entsteht durch den `commit --amend`.",
"Beachte den geschilderten Zielzustand. Da wir die Commits zweimal umsortieren, bekommen sie jedes Mal ein Apostroph hinzugefügt (weil sie jedes Mal kopiert werden). Ein weiteres Apostroph entsteht durch den `git commit --amend`.",
"",
"Zuguterletzt noch eine Bemerkung: ich kann Level nur auf Struktur und Apostroph-Differenz prüfen. So lange wie dein `master` am Ende dieselbe Struktur und Apostroph-Differenz aufweist wie der Ziel-`master`, ist der Level bestanden."
"Zuguterletzt noch eine Bemerkung: ich kann Level nur auf Struktur und Apostroph-Differenz prüfen. So lange wie dein `main` am Ende dieselbe Struktur und Apostroph-Differenz aufweist wie der Ziel-`main`, ist der Level bestanden."
]
}
},
@ -239,7 +317,7 @@ exports.level = {
"この困難な状況を、以下の手順で克服することを考えます:",
"",
"* `git rebase -i`を使って順番を変更する。これで、変更をかけたいコミットを一番先頭に持ってくる。",
"* `commit --amend`コマンドで僅かな変更を行う",
"* `git commit --amend`コマンドで僅かな変更を行う",
"* `git rebase -i`コマンドを再度使って、先頭に持ってきていたコミットを元に戻す",
"* 最後に、レベルクリアのためにmasterブランチを先頭に持ってくる",
"",
@ -272,14 +350,14 @@ exports.level = {
"我们可以通过下面的方法来克服困难:",
"",
"* 先用 `git rebase -i` 将提交重新排序,然后把我们想要修改的提交记录挪到最前",
"* 然后用 `commit --amend` 来进行一些小修改",
"* 然后用 `git commit --amend` 来进行一些小修改",
"* 接着再用 `git rebase -i` 来将他们调回原来的顺序",
"* 最后我们把 master 移到修改的最前端(用你自己喜欢的方法),就大功告成啦!",
"* 最后我们把 main 移到修改的最前端(用你自己喜欢的方法),就大功告成啦!",
"",
"当然完成这个任务的方法不止上面提到的一种(我知道你在看 cherry-pick 啦),之后我们会多点关注这些技巧啦,但现在暂时只专注上面这种方法。",
"最后有必要说明一下目标状态中的那几个`'` —— 我们把这个提交移动了两次,每移动一次会产生一个 `'`;而 C2 上多出来的那个是我们在使用了 amend 参数提交时产生的,所以最终结果就是这样了。",
"",
"也就是说,我在对比结果的时候只会对比提交树的结构,对于 `'` 的数量上的不同,并不纳入对比范围内。只要你的 `master` 分支结构与目标结构相同,我就算你通过。"
"也就是说,我在对比结果的时候只会对比提交树的结构,对于 `'` 的数量上的不同,并不纳入对比范围内。只要你的 `main` 分支结构与目标结构相同,我就算你通过。"
]
}
}
@ -306,9 +384,9 @@ exports.level = {
"為了克服這個困難,我們可以按照下面的方法來做:",
"",
"* 先用 `git rebase -i` 將 commit 重新排序,然後把我們想要修改的 commit 移到最前面",
"* 然後用 `commit --amend` 來進行一些修改",
"* 然後用 `git commit --amend` 來進行一些修改",
"* 接著再用 `git rebase -i` 來將他們按照最開始的順序重新排好",
"* 最後我們把 master 移到這個修改的最前端(用你自己喜歡的方法),就大功告成啦!",
"* 最後我們把 main 移到這個修改的最前端(用你自己喜歡的方法),就大功告成啦!",
"",
"當然還有許多方法可以完成這個任務(我知道你在想 cherry-pick 啦),之後我們會多點關注這些技巧啦,但現在暫時只注意上面這種方法。",
"",
@ -328,7 +406,7 @@ exports.level = {
"",
"이번에도 꽤 자주 발생하는 상황입니다. `newImage`와 `caption` 브랜치에 각각의 변경내역이 있고 서로 약간 관련이 있어서, 저장소에 차례로 쌓여있는 상황입니다.",
"",
"때로는 이전 커밋의 내용을 살짝 바꿔야하는 골치아픈 상황에 빠지게 됩니다. 이번에는 디자인 쪽에서 우리의 작업이력(history)에서는 이미 한참 전의 커밋 내용에 있는 `newImage`의 크기를 살짝 바꿔달라는 요청이 들어왔습니다."
"때로는 이전 커밋의 내용을 살짝 바꿔야하는 골치아픈 상황에 빠지게 됩니다. 이번에는 디자인 쪽에서 우리의 작업이력(history)에서는 이미 한참 전의 커밋 내용에 있는 `newImage`의 크기를 살짝 바꿔 달라는 요청이 들어왔습니다."
]
}
},
@ -339,9 +417,9 @@ exports.level = {
"이 문제를 다음과 같이 풀어봅시다:",
"",
"* `git rebase -i` 명령으로 우리가 바꿀 커밋을 가장 최근 순서로 바꾸어 놓습니다",
"* `commit --amend` 명령으로 커밋 내용을 정정합니다",
"* `git commit --amend` 명령으로 커밋 내용을 정정합니다",
"* 다시 `git rebase -i` 명령으로 이 전의 커밋 순서대로 되돌려 놓습니다",
"* 마지막으로, master를 지금 트리가 변경된 부분으로 이동합니다. (편하신 방법으로 하세요)",
"* 마지막으로, main을 지금 트리가 변경된 부분으로 이동합니다. (편하신 방법으로 하세요)",
"",
"이 목표를 달성하기 위해서는 많은 방법이 있는데요(체리픽을 고민중이시죠?), 체리픽은 나중에 더 살펴보기로 하고, 우선은 위의 방법으로 해결해보세요.",
"",
@ -372,13 +450,13 @@ exports.level = {
"Преодолеть эти трудности можно следующим образом:",
"",
"* Переставить коммит так, чтобы нужный находился наверху при помощи `git rebase -i`",
"* Внести изменения при помощи `commit --amend`",
"* Внести изменения при помощи `git commit --amend`",
"* Переставить всё обратно при помощи `git rebase -i`",
"* И наконец, переместить master на изменённую часть дерева, чтобы закончить уровень.",
"* И наконец, переместить main на изменённую часть дерева, чтобы закончить уровень.",
"",
"Это задание можно выполнить несколькими способами (и, гляжу, ты посматриваешь на cherry-picking), но сейчас сосредоточься на вышеописанном методе.",
"",
"Обрати внимание на итоговое состояние в этом уровне так как мы дважды перемещаем коммиты, оба они получат по апострофу. Ещё один апостроф добавляется, когда мы делаем `commit --amend`.",
"Обрати внимание на итоговое состояние в этом уровне так как мы дважды перемещаем коммиты, оба они получат по апострофу. Ещё один апостроф добавляется, когда мы делаем `git commit --amend`.",
"",
"Важно, чтобы совпадало не только дерево коммитов, но и количество апострофов."
]
@ -407,14 +485,82 @@ exports.level = {
"Ми поборимо цю складність наступним чином:",
"",
"* Ми відсортуємо коміти таким чином, щоб той, який ми хочемо змінити, був останнім за допомогою `git rebase -i`",
"* Ми виконаємо `commit --amend` щоб внести невелику правку до останнього коміту",
"* Ми виконаємо `git commit --amend` щоб внести невелику правку до останнього коміту",
"* Тоді ми відсортуємо коміти в попередньому порядку, за допомогою `git rebase -i`",
"* І на останок, ми пересунемо master на змінену частину дерева щоб закінчити цей рівень(ти можеш вибрати метод)",
"* І на останок, ми пересунемо main на змінену частину дерева щоб закінчити цей рівень(ти можеш вибрати метод)",
"",
"Насправді є кілька способів як виконати поставлену задачу (Я бачу, ти поглядаєш на cherry-pick), і ми розберемося з ними всіма трохи пізніше, але зараз скористаймося саме цим методом.",
"Зверни увагу на фінальний стан в цьому рівні -- позаяк ми перемістили коміти двічі, кожен з них отримає по апострофу. Ще один апостроф додасться коли ми виконаємо commit --amend.",
"",
"Враховуючи сказане вище, я буду порівнювати дерево як за назвою коміта, так і за кількістю апострофів. Щойно дерево цілей та master співпадуть, ти пройдеш цей рівень."
"Враховуючи сказане вище, я буду порівнювати дерево як за назвою коміта, так і за кількістю апострофів. Щойно дерево цілей та main співпадуть, ти пройдеш цей рівень."
]
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Tung hứng Commit",
"",
"Có một tình huống xảy ra khá thường xuyên. Bạn có vài thay đổi trên (`newImage`) và một vài thay đổi khác trên (`caption`) và chúng lại liên quan đến nhau, nên chúng nằm chồng lên nhau trong kho của bạn (một lại nối một).",
"",
"Tréo ngoe là bạn lại phải điều chỉnh một chút ở commit trước. Giả sử như tay thiết kết muốn ta đổi chiều của `newImage` một chút, mặc dù commit ấy đã xưa lắm rồi!!"
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Để khắc phục khó khăn này ta có thể làm như sau:",
"",
"* Ta sẽ dùng `git rebase -i` sắp xếp lại commit để cái ta cần sửa sẽ nằm trên cùng",
"* Ta sẽ dùng `git commit --amend` tạo ra một điều chỉnh nhỏ",
"* Sau đó ta sẽ lại sắp xếp lại commit như trước bằng cách dùng `git rebase -i`",
"* Cuối cùng, ta sẽ chuyển `main` tới phần đã cập nhật để hoàn thành cấp độ (dùng cách nào tùy bạn)",
"",
"Có nhiều cách để hoàn thành mục tiêu (Tôi thấy bạn hấp háy sang cherry-pick rồi đấy), rồi ta sẽ thấy chúng nhiều hơn, nhưng giờ hãy cứ tập trung vào kỹ thuật này đã.",
"Sau cùng thì, để ý các dấu nháy đơn(') chứ?-- vì ta đã chuyển commit 2 lần, nên chúng có thêm một dấu nháy đơn. Và một dấu nữa cho commit mà ta đã sửa đổi, thế là ta có trạng thái cuối cùng của cây lịch sử ",
"",
"Nói cách khác, khi tôi so sánh kết quả, tôi chỉ so sánh cấu trúc của cây lịch sử. Sự khác biệt về số lượng `'` không được bao gồm trong so sánh. Miễn là cấu trúc nhánh `main` của bạn giống với cấu trúc đích, tôi sẽ vẫn để bạn qua bài."
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Žongliranje s Commiti",
"",
"Tu je še ena situacija, ki se dogaja kar pogosto. Imaš nekaj sprememb (`newImage`) in še nekaj drugih sprememb (`caption`), ki so povezane in zložene druga na drugo v tvojem repozitoriju.",
"",
"Včasih se zgodi, da bi rad naredil manjšo spremembo na zgodnejšem commitu. V tem primeru si naš dizajner želi, da spremenimo dimenzije slike `newImage`, čeprav je commit daleč nazaj v naši zgodovini!!"
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ta izziv bomo rešili takole:",
"",
"* Preuredili bomo commite tako, da bo tisti, ki ga želimo spremeniti, na vrhu z `git rebase -i`",
"* Izvedli bomo `git commit --amend`, da naredimo naš popravek",
"* Nato bomo preuredili commite nazaj v začetno stanje z `git rebase -i`",
"* Za konec bomo premaknili main na ta posodobljen del drevesa, da zaključimo stopnjo (z metodo po tvoji izbiri)",
"",
"Obstaja več načinov, da dosežemo ta cilj (vidim te kako gledaš cherry-pick) s katerimi se bomo ukvarjali kasneje, ampak za zdaj se osredotočimo na to tehniko.",
"In nenazadnje, bodi pozoren na ciljno stanje -- ker premaknemo commit dvakrat, oba dobita pripet opuščaj zgoraj. Še eden je dodan za ammendan commit, torej skupno tri.",
"",
"Sedaj lahko primerjam stopnje po strukturi in relativni spremembi opuščajev. Dokler ima `main` branch na tvojem drevesu enako strukturo in število opuščajev, dobiš vse točke."
]
}
}

View file

@ -1,6 +1,6 @@
exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C3%27%22%2C%22id%22%3A%22master%22%7D%2C%22newImage%22%3A%7B%22target%22%3A%22C2%22%2C%22id%22%3A%22newImage%22%7D%2C%22caption%22%3A%7B%22target%22%3A%22C3%22%2C%22id%22%3A%22caption%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%27%22%7D%2C%22C2%27%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%27%27%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C2%27%27%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",
"solutionCommand": "git checkout master;git cherry-pick C2;git commit --amend;git cherry-pick C3",
"solutionCommand": "git checkout main;git cherry-pick C2;git commit --amend;git cherry-pick C3",
"disabledMap": {
"git revert": true
},
@ -9,7 +9,7 @@ exports.level = {
"goalAsserts": {
"master": [
function(data) {
return data.C2 > data.C3;
return data.C2 >= data.C3;
},
function(data) {
return data.C2 > data.C1;
@ -21,26 +21,34 @@ exports.level = {
"en_US": "Juggling Commits #2",
"fr_FR": "Jongler avec les commits #2",
"es_AR": "Haciendo malabares con los commits #2",
"es_ES": "Haciendo malabares con los commits #2",
"pt_BR": "Malabarismo com commits #2",
"gl" : "Argallando cos commits #2",
"de_DE": "Jonglieren mit Commits Teil 2",
"ja": "コミットをやりくりする その2",
"zh_CN": "提交的技巧 #2",
"zh_TW": "commit 的戲法 #2",
"ru_RU": "Жонглируем коммитами №2",
"uk": "Жонглюємо комітами #2"
"uk": "Жонглюємо комітами #2",
"vi": "Tung hứng commit #2",
"sl_SI": "Žongliranje s Commiti #2"
},
"hint": {
"en_US": "Don't forget to forward master to the updated changes!",
"fr_FR": "N'oubliez pas de forwarder la branch master dans la nouvelle branch",
"es_AR": "¡No te olvides de avanzar master a los cambios actualizados!",
"pt_BR": "Não se esqueça de avançar a referência do master para as mudanças efetuadas!",
"de_DE": "Vergiss nicht den master auf die aktuelle Version vorzuspulen",
"en_US": "Don't forget to forward main to the updated changes!",
"fr_FR": "N'oubliez pas d'appliquer les changements depuis la branche main",
"es_AR": "¡No te olvides de avanzar main a los cambios actualizados!",
"es_ES": "¡No te olvides de avanzar main a los cambios actualizados!",
"pt_BR": "Não se esqueça de avançar a referência do main para as mudanças efetuadas!",
"gl" : "¡Non te esquezas de avanzar main ós cambios actualizados!",
"de_DE": "Vergiss nicht den main auf die aktuelle Version vorzuspulen",
"ja": "masterのポインタを先に進めることを忘れずに",
"ko": "master를 변경 완료한 커밋으로 이동(forward)시키는 것을 잊지 마세요!",
"zh_CN": "别忘记了将 master 快进到最新的更新上!",
"zh_TW": "別忘記了將 master 推到最新的 commit 上面!",
"ru_RU": "Не забудь переместить master на последние изменения.",
"uk": "Не забудь перемістити master на останні зміни!"
"ko": "main을 변경 완료한 커밋으로 이동(forward)시키는 것을 잊지 마세요!",
"zh_CN": "别忘记了将 main 快进到最新的更新上!",
"zh_TW": "別忘記了將 main 推到最新的 commit 上面!",
"ru_RU": "Не забудь переместить main на последние изменения.",
"uk": "Не забудь перемістити main на останні зміни!",
"vi": "Đừng quên đẩy nhánh main lên cập nhật mới nhất!",
"sl_SI": "Ne pozabi prestaviti main naprej na posodobljene spremembe."
},
"startDialog": {
"en_US": {
@ -55,7 +63,7 @@ exports.level = {
"",
"As you saw in the last level, we used `rebase -i` to reorder the commits. Once the commit we wanted to change was on top, we could easily --amend it and re-order back to our preferred order.",
"",
"The only issue here is that there is a lot of reordering going on, which can introduce rebase conflicts. Let's look at another method with `git cherry-pick`"
"The only issue here is that there is a lot of reordering going on, which can introduce rebase conflicts. Let's look at another method with `git cherry-pick`."
]
}
},
@ -68,10 +76,10 @@ exports.level = {
"Here's a small refresher demo:"
],
"afterMarkdowns": [
"Nice! Let's move on"
"Nice! Let's move on."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -80,7 +88,7 @@ exports.level = {
"markdowns": [
"So in this level, let's accomplish the same objective of amending `C2` once but avoid using `rebase -i`. I'll leave it up to you to figure it out! :D",
"",
"Remember, the exact number of apostrophe's (') on the commit are not important, only the relative differences. For example, I will give credit to a tree that matches the goal tree but has one extra apostrophe everywhere"
"Remember, the exact number of apostrophe's (') on the commit are not important, only the relative differences. For example, I will give credit to a tree that matches the goal tree but has one extra apostrophe everywhere."
]
}
}
@ -98,7 +106,7 @@ exports.level = {
"",
"Comme vu dans le niveau précédent, nous utilisons `rebase -i` pour réordonner les commits. Une fois que le commit à modifier est celui à la tête, nous pouvons facilement faire un --amend et réordonner dans l'ordre voulu.",
"",
"La difficulté ici est qu'il y a beaucoup de changements, ce qui peut introduire des conflits de rebase. Essayons avec l'autre méthode `git cherry-pick`"
"La difficulté ici est qu'il y a beaucoup de changements, ce qui peut introduire des conflits de rebase. Essayons avec l'autre méthode `git cherry-pick`."
]
}
},
@ -114,7 +122,7 @@ exports.level = {
"Bien ! continuons."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -141,7 +149,7 @@ exports.level = {
"",
"Como viste en el último nivel, usamos `rebase -i` para reordenar los commits. Una vez que el commit que queríamos cambiar estaba arriba de todo, pudimos `--amend`earlo fácilmente y reordenarlo a como queríamos.",
"",
"El único problema con esto es que hay mucho reordenamiento, que puede generar conflictos al rebasear. Veamos otro método usando `git cherry-pick`"
"El único problema con esto es que hay mucho reordenamiento, que puede generar conflictos al rebasear. Veamos otro método usando `git cherry-pick`."
]
}
},
@ -157,7 +165,7 @@ exports.level = {
"¡Bien! Sigamos..."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -166,7 +174,50 @@ exports.level = {
"markdowns": [
"Entonces, en este nivel vamos a lograr el mismo objetivo de corregir `C2`, pero sin usar `rebase -i`. Te dejo a vos el darte cuenta cómo :D",
"",
"Acordate, la cantidad exacta de apóstrofes (') en el commit no es importante, sólo la diferencia relativa. Por ejemplo, le voy a dar puntaje a un árbol que matchee el objetivo pero cuyos commits tengan todos un apóstrofe extra"
"Acordate, la cantidad exacta de apóstrofes (') en el commit no es importante, sólo la diferencia relativa. Por ejemplo, le voy a dar puntaje a un árbol que matchee el objetivo pero cuyos commits tengan todos un apóstrofe extra."
]
}
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Haciendo malabares con los commits #2",
"",
"*Si no completaste Haciendo malabares con los commits #1 (el nivel anterior), hazlo antes de continuar*",
"",
"Como viste en el último nivel, usamos `rebase -i` para reordenar los commits. Una vez que el commit que queríamos cambiar se encontraba arriba de todo, pudimos `--amend`earlo fácilmente y reordenarlo a como queríamos.",
"",
"El único problema con esto es que hay mucho reordenamiento, que puede generar conflictos al rebasear. Veamos otro método usando `git cherry-pick`."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Recuerda que git cherry-pick va a traer un commit de cualquier parte del árbol sobre HEAD (siempre que ese otro commit no sea un ancestro de HEAD).",
"",
"Una pequeña demo para refrescar la idea:"
],
"afterMarkdowns": [
"¡Bien! Sigamos..."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Entonces, en este nivel vamos a lograr el mismo objetivo de corregir `C2`, pero sin usar `rebase -i`. Te dejo a ti el darte cuenta cómo :D",
"",
"Recuerda, la cantidad exacta de apóstrofes (') en el commit no es importante, sólo la diferencia relativa. Por ejemplo, le voy a dar una puntuación a un árbol que coincida con el objetivo pero cuyos commits tengan todos un apóstrofe extra."
]
}
}
@ -184,7 +235,7 @@ exports.level = {
"",
"Como você viu no nível anterior, usamos `rebase -i` para reordenar os commits. Uma vez que o commit que queríamos mudar estava no topo, pudemos facilmente usar o `--amend` e depois reordená-lo de volta para obter nossa ordem preferida.",
"",
"O único problema aqui é que há muita reordenação ocorrendo, o que pode introduzir conflitos de rebase. Vamos dar uma olhada em outro método, usando o `git cherry-pick`"
"O único problema aqui é que há muita reordenação ocorrendo, o que pode introduzir conflitos de rebase. Vamos dar uma olhada em outro método, usando o `git cherry-pick`."
]
}
},
@ -197,10 +248,10 @@ exports.level = {
"Aqui está uma demonstração para refrescar sua memória:"
],
"afterMarkdowns": [
"Ótimo! Vamos em frente"
"Ótimo! Vamos em frente."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -209,7 +260,50 @@ exports.level = {
"markdowns": [
"Então, neste nível, vamos alcançar o mesmo objetivo de fazer \"amend\" no `C2`, mas evitaremos usar o `rebase -i`. Agora vou deixar com você a tarefa de descobrir como fazer! :D",
"",
"Lembre-se, o número exato de apóstrofos (') nos commits não é importante, apenas as diferenças relativas. Por exemplo, darei todos os pontos nesta tarefa se você obtiver o mesmo resultado da árvore da visualização de objetivo com um apóstrofo extra em todos os commits"
"Lembre-se, o número exato de apóstrofos (') nos commits não é importante, apenas as diferenças relativas. Por exemplo, darei todos os pontos nesta tarefa se você obtiver o mesmo resultado da árvore da visualização de objetivo com um apóstrofo extra em todos os commits."
]
}
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Argallando cos commits #2",
"",
"*No caso de non ter rematado o tema anterior (Argallando cos commits #1), por favor faino antes de continuar*.",
"",
"Como puideches ver no anterior tema, usamos `rebase -i` para reordear os commits. Unha vez que atopamos o commit que queriamos modificar, puidemos empregar sinxelamente o `--amend`, e depois reordenalo de volta para obter a nosa orde preferida.",
"",
"O único problema aquí é que hai moita reordenación ocorrendo, o que pode introducir conflitos no rebase. Imos votar unha ollada a outro método, o uso de `git cherry-pick`."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Lembra que `git cherry-pick` copiará un commit de qualquera lugar na árbore enriba do HEAD (sempre e cando non sexa ancestro do HEAD).",
"",
"Aquí está unha demostración para que refresques a memoria:"
],
"afterMarkdowns": [
"¡A tope! Seguimos."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Entón, neste nivel, imos completar o mesmo obxectivo que facendo \"amend\" no `C2`, pero evitando facer o `rebase -i`. Agora deixámoste que lle des os miolos para sacar o exercicio! :D",
"",
"Recorda, o número exacto de apóstrofos (') nos commits non é importante, só as diferencias relativas. Por exemplo, levarás todos os puntos desta tarefa se obtés o mesmo resultado da árbore que se mostra na visualización do exercicio con un apóstrofo extra en tódolos commits."
]
}
}
@ -225,7 +319,7 @@ exports.level = {
"",
"Du solltest \"Jonglieren mit Commits\" (den vorherigen Level) bestanden haben, bevor du dich an diesem hier versuchst.",
"",
"Wie du im letzten Level gesehen hast haben wir `git rebase -i` genutzt, um die Commits neu anzuordnen. Sobald der Commit, den wir ändern wollte, ganz oben war, konnten wir das auch einfach mit `git commit --amend` tun. Danach haben wir die alte Reihenfolge wiederhergestellt.",
"Wie du im letzten Level gesehen hast, haben wir `git rebase -i` genutzt, um die Commits neu anzuordnen. Sobald der Commit, den wir ändern wollten, ganz oben war, konnten wir ihn einfach mit `git commit --amend` anpassen. Danach haben wir die alte Reihenfolge wiederhergestellt.",
"",
"Das einzige Problem ist hier, dass da eine Menge Umsortieren stattfindet, was zu Rebase-Konflikten führen kann. Schauen wir uns also eine Methode mit `git cherry-pick` an."
]
@ -235,7 +329,7 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Wie du dich erinnerst macht `git cherry-pick` eine Kopie des angegebenen Commits und fügt sie an `HEAD` an (es sei denn der Commit ist ein Vorgänger von `HEAD`).",
"Wie du dich erinnerst, macht `git cherry-pick` eine Kopie des angegebenen Commits und fügt sie an `HEAD` an (es sei denn der Commit ist ein Vorgänger von `HEAD`).",
"",
"Hier eine kleine Demo zur Erinnerung:"
],
@ -243,7 +337,7 @@ exports.level = {
"Schick! Und weiter geht's."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -286,7 +380,7 @@ exports.level = {
"できました!次へ進みましょう"
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -307,7 +401,7 @@ exports.level = {
"markdowns": [
"## 提交的技巧 #2",
"",
"*如果你还没有完成“提交的技巧 #1”前一关的话通过以后再来!*",
"*如果你还没有完成“提交的技巧 #1”前一关的话通过以后再来!*",
"",
"正如你在上一关所见到的,我们可以使用 `rebase -i` 对提交记录进行重新排序。只要把我们想要的提交记录挪到最前端,我们就可以很轻松的用 `--amend` 修改它,然后把它们重新排成我们想要的顺序。",
"",
@ -327,7 +421,7 @@ exports.level = {
"afterMarkdowns": [
"看到了吧?我们继续"
],
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -370,7 +464,7 @@ exports.level = {
"afterMarkdowns": [
"太棒了,我們繼續吧!"
],
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -411,7 +505,7 @@ exports.level = {
"좋아요! 계속할게요"
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -452,7 +546,7 @@ exports.level = {
"Ок! Едем дальше!"
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -479,7 +573,7 @@ exports.level = {
"",
"Як ти бачив в попередньому рівні, ми використали `rebase -i` щоб впорядкувати набір комітів. Як тільки потрібний коміт опиняється вгорі, його досить легко змінити за допомогою --amend й потім відсортувати коміти в попередньому порядку.",
"",
"Єдина проблема з таким підходом полягає в тому, що виконується досить багато перестановок комітів, що може призвести до конфліктів при виконанні rebase. Спробуймо інший підхід який використовує `git cherry-pick`"
"Єдина проблема з таким підходом полягає в тому, що виконується досить багато перестановок комітів, що може призвести до конфліктів при виконанні rebase. Спробуймо інший підхід який використовує `git cherry-pick`."
]
}
},
@ -495,7 +589,7 @@ exports.level = {
"Добре! Продовжуємо"
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout master; git commit"
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
@ -509,6 +603,92 @@ exports.level = {
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Tung hứng Commit #2",
"",
"*Nếu bạn vẫn chưa hoàn thành Tung hứng Commit #1 (cấp độ trước), hãy làm nó trước khi tiếp tục*",
"",
"Như bạn đã thấy ở cấp độ trước, ta dùng `rebase -i` để sắp xếp lại các commit. Một khi commit mà ta muốn sửa đã ở trên cùng, ta có thể dễ dàng --chỉnh sửa(amend) nó và sau đó sắp xếp lại trật tự lúc trước.",
"",
"Nhưng mà vẫn tồn tại vấn đề khi mà ta sắp xếp quá nhiều, điều này có thể dẫn đến xung đột khi rebase. Thử dùng cách khác với `git cherry-pick` nào"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Hãy nhớ rằng cherry-pick sẽ thả commit ở bất cứ đâu xuống dưới HEAD (miễn là nó không phải cha ông hay tổ tiên gì của HEAD).",
"",
"Hãy xem thử minh họa nhỏ sau:"
],
"afterMarkdowns": [
"Hay! Tiếp tục nào"
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Vậy thì ở cấp độ này, hãy làm hoàn thành mục tiêu tương tự là chỉnh sửa `C2` một lần nhưng hãy tránh dùng `rebase -i`. Tự tìm cách đi nhé! :D",
"",
"Nhớ rằng, số lượng dấu nháy dơn (') trên commit không quan trọng, quan trọng là mối tương liên các tham chiếu. Nói cách khác, kể cả bất cứ commit nào của bạn có thêm một đấu(') tôi vẫn công nhận đáp án của bạn"
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Žongliranje s Commiti #2",
"",
"Če še nisi končal Žongliranje s Commiti #1 (prejšnjo stopnjo), jo končaj pred nadaljevanjem",
"",
"Kot si videl v prejšnji stopnji, smo uporabili `rebase -i` za preureditev commitov. Ko je bil commit, ki smo ga želeli spremeniti, na vrhu, smo preprosto uporabili --amend in preuredili nazaj v naše željeno stanje.",
"",
"Edini problem tu je, da je veliko prerazporejanja, kar lahko povzroči rebase konflikte. Poglejmo si še eno drugo tehniko imenovano `git cherry-pick`."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Git cherry-pick bo skopiral commit iz bilokaterega mesta na drevesu na HEAD (seveda dokler ni ta commit že prednik HEAD).",
"",
"Tu je mali osvežitveni primer:"
],
"afterMarkdowns": [
"Odlično! Nadaljujmo ..."
],
"command": "git cherry-pick C2",
"beforeCommand": "git checkout -b bugFix; git commit; git checkout main; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Torej v tej stopnji bi radi enako spremenili `C2`, ampak tokrat brez uporabe `rebase -i`. Kako to narediti, prepustim tebi! :D",
"",
"Točno število opuščajev (') na commitu ni pomembno, pomembna je samo relativna sprememba. Naprimer, vse točko bom dal tudi za drevo, ki ustreza ciljenmu drevesu, a ima povsod dodaten opuščaj."
]
}
}
]
}
}
};

View file

@ -1,19 +1,23 @@
exports.level = {
exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C5\",\"id\":\"master\",\"remoteTrackingBranchID\":null},\"side\":{\"target\":\"C3\",\"id\":\"side\",\"remoteTrackingBranchID\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C1\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\",\"C4\"],\"id\":\"C5\"}},\"tags\":{\"v1\":{\"target\":\"C2\",\"id\":\"v1\",\"type\":\"tag\"},\"v0\":{\"target\":\"C1\",\"id\":\"v0\",\"type\":\"tag\"}},\"HEAD\":{\"target\":\"C2\",\"id\":\"HEAD\"}}",
"solutionCommand": "git tag v1 side~1;git tag v0 master~2;git checkout v1",
"solutionCommand": "git tag v1 side~1;git tag v0 main~2;git checkout v1",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C5\",\"id\":\"master\",\"remoteTrackingBranchID\":null},\"side\":{\"target\":\"C3\",\"id\":\"side\",\"remoteTrackingBranchID\":null}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C1\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\",\"C4\"],\"id\":\"C5\"}},\"tags\":{},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"name": {
"en_US": "Git Tags",
"de_DE": "Git Tags",
"ja" : "Gitのタグ",
"es_AR": "Tags en git",
"es_ES": "Tags en git",
"pt_BR": "Tags no Git",
"gl" : "Etiquetas en git",
"fr_FR": "Git Tags",
"zh_CN": "Git Tag",
"zh_TW": "git tag",
"ru_RU": "git tag",
"ko" : "Git 태그",
"uk" : "Git Tags"
"uk" : "Git Tags",
"vi" : "Tag trong Git",
"sl_SI": "Git Tagi"
},
"hint": {
"en_US": "you can either check out the commit directly or simply checkout the tag!",
@ -21,12 +25,16 @@
"de_DE": "Du kannst den Checkout entweder direkt auf den Commit oder das Tag machen.",
"ja" : "コミットを直接チェックアウトできますが、簡単にタグでチェックアウトすることも可能!",
"es_AR": "Podés checkoutear directamente el commit, ¡o simplemente el tag!",
"es_ES": "Puedes hacer checkout directamente el commit, ¡o simplemente el tag!",
"pt_BR": "Você pode fazer checkout diretamente no commit ou na tag correspondente!",
"gl" : "Podes saltar directamente ó commit, ¡ou a etiqueta, que é máis doado!",
"zh_TW": "你可以直接 checkout 到 commit 上,或是簡單的 checkout 到 tag 上",
"zh_CN": "你可以直接 checkout 到 commit 上,或是简单地 checkout 到 tag 上",
"ru_RU": "Можно сделать checkout напрямую на коммит или же на тег",
"ko" : "커밋을 직접 또는 태그를 이용해서 체크아웃할수 있습니다!",
"uk" : "ти можеш або зробити checkout коміта напряму чи просто зачекаутити таг!"
"uk" : "ти можеш або зробити checkout коміта напряму чи просто зачекаутити таг!",
"vi" : "Bạn có thể chuyển trực tiếp sang commit hoặc đơn giản là chuyển sang tag!",
"sl_SI": "Checkoutaš lahko neposredno commit ali pa preprosto njegov tag!"
},
"startDialog": {
"en_US": {
@ -60,10 +68,10 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Let's try making a tag at `C1` which is our version 1 prototype"
"Let's try making a tag at `C1` which is our version 1 prototype."
],
"afterMarkdowns": [
"There! Quite easy. We named the tag `v1` and referenced the commit `C1` explicitly. If you leave the commit off, git will just use whatever `HEAD` is at"
"There! Quite easy. We named the tag `v1` and referenced the commit `C1` explicitly. If you leave the commit off, git will just use whatever `HEAD` is at."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
@ -100,7 +108,7 @@
"type": "ModalAlert",
"options": {
"markdowns": [
"Vous l'avez deviné ! Git tags offre cette fonctionnalité : les tags marquent à jamais certains commits comme \"milestone\" auxquels vous pouvez vous référez comme à des branches.",
"Vous l'avez deviné ! Les tags Git offrent cette fonctionnalité : les tags marquent à jamais certains commits comme \"milestone\" (étape clé) auxquels vous pouvez vous référer comme à des branches.",
"",
"Encore plus important, il sont définitifs. Vous ne pouvez donc pas rajouter de commit dans un tag : les tags sont un peu comme un pointeur définitif dans l'arbre des commits.",
"",
@ -112,7 +120,7 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Essayons de faire un tag sur C1 (qui représente la version 1 de notre prototype)"
"Essayons de faire un tag sur C1 (qui représente la version 1 de notre prototype)."
],
"afterMarkdowns": [
"Voila, facile non ? Nous nommons le tag `v1` et il pointe vers le commit `C1`. Si vous ne spécifiez pas le commit, le tag pointera là où se trouve `HEAD`."
@ -271,7 +279,7 @@
"Creemos un tag en `C1`, que es nuestro prototipo de la versión 1"
],
"afterMarkdowns": [
"¡Ahí está! Bastante simple. Nombramos al tag `v1` y referenciamos explícitamente al commit `C1`. Si no especificás el commit, git va a usar al apuntado por `HEAD`"
"¡Ahí está! Bastante simple. Nombramos al tag `v1` y referenciamos explícitamente al commit `C1`. Si no especificás el commit, git va a usar al apuntado por `HEAD`."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
@ -289,6 +297,58 @@
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Tags en git",
"",
"Como aprendiste en lecciones anteriores, las ramas pueden moverse fácilmente, y en general van referenciando distintos commits a medida que el trabajo se va completando en ellas. Las ramas cambian fácilmente, suelen ser temporales, y siempre cambiantes.",
"",
"Si ese es el caso, te podrías estar preguntando si hay una manera de marcar *permanentemente* puntos en la historia de tu proyecto. Para cosas como releases mayores o grandes merges, ¿hay algún modo de marcar esos commits con algo más permanente que un branch?",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"¡Seguro que hay! Los tags de git soportan exactamente este caso de uso -- marcan (bastante) permanentemente determinados commits como \"hitos\" que puedes referenciar como a un branch.",
"",
"Aún más importante, los tags no avanzan cuando se crean nuevos commits. No puedes hacer checkout a un tag y completar el trabajo en ese tag - los tags son marcas fijas en el árbol de commits que designan ciertos puntos.",
"",
"Veamos cómo se ven los tags en práctica..."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Creemos un tag en `C1`, que es nuestro prototipo de la versión 1"
],
"afterMarkdowns": [
"¡Ahí está! Bastante simple. Nombramos al tag `v1` y referenciamos explícitamente al commit `C1`. Si no especificas el commit, git va a usar al apuntado por `HEAD`."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para este nivel, simplemente crea los tags en la visualización final y después haz checkout con `v1`. Observa cómo entras en el estado detached -- esto es porque no puedes hacer commit directamente sobre el tag `v1`.",
"",
"En el próximo nivel vamos a examinar un caso de uso más interesante para los tags."
]
}
}
]
},
"pt_BR": {
"childViews": [
{
@ -323,7 +383,7 @@
"Criemos uma tag em `C1`, que é nosso protótipo da versão 1"
],
"afterMarkdowns": [
"Aqui! Bem fácil. Nós chamamos a tag de `v1` e referenciamos o commit `C1` explicitamente. Se você chamar o comando sem especificar um commit, o git vai usar seja lá qual commit para o qual o `HEAD` estiver apontando"
"Aqui! Bem fácil. Nós chamamos a tag de `v1` e referenciamos o commit `C1` explicitamente. Se você chamar o comando sem especificar um commit, o git vai usar seja lá qual commit para o qual o `HEAD` estiver apontando."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
@ -341,6 +401,58 @@
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Etiquetas en Git",
"",
"Como aprendiches nas leccións previas, as ramas pódense mover sinxelamente, e xeralmente refírense a distintos commits según vas completando o código. As ramas mutan con facilidade, soen ser temporais, e sempre cambiantes.",
"",
"Se estamos nese caso, podes preguntarte se existe unha forma de marcar *permanentemente* puntos históricos no proxecto. Para cousas como grandes entregas ou grandes merges, ¿existe algunha forma de marcar commits con algo máis permanente que unha rama?",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Acertaches seguro, ¡si que existe! As etiquetas de git foron creadas para ese propósito -- elas marcan de forma (relativamente) permanente algún commits coma se fosen \"marcos das fincas\" (\"milestones\") nun campeiro, e podes facer referencias a elas mellor que o catastro.",
"",
"É moi importante saber que, as etiquetas non avanzan cando se crean novos commits. Non podes facer \"checkout\" nun tag e completar o traballo de esa etiqueta cun commit amend ou rebasándoo -- as etiquetas existen como áncoras na árbore de commits que están pegadas a certos puntos.",
"",
"Vexamos como se comportan as etiquetas na práctica."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Creamos un tag na rama `C1`, que é o noso prototipo da versión 1"
],
"afterMarkdowns": [
"¡Ahí o tes!. Sinxelo. Nomeamos a etiqueta de `v1` e referenciamos o commit `C1` explícitamente. Se non indicas o commit, git vai empregar o commit onde está situado o `HEAD`."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar esta tarefa, crea as etiquetas amosadas na visualización do obxectivo, e entón fai checkout en `v1`. Mira que terminas no estado \"Detached HEAD\" -- eso é porque non podes facer commit directamente na etiqueta `v1`.",
"",
"No próximo nivel, examinaremos un caso de uso máis interesante para as etiquetas."
]
}
}
]
},
"de_DE": {
"childViews": [
{
@ -349,7 +461,7 @@
"markdowns": [
"## Git Tags",
"",
"Wie du aus den vorhergehenden Levels weißt sind Branches einfach durch die Gegend zu schieben und zeigen auf verschiedene Commits, während die Arbeit in ihnen fortschreitet. Ein Branch wird oft verändert, manchmal nur temporär, und ist ständig in Bewegung.",
"Wie du aus den vorhergehenden Levels weißt, sind Branches einfach durch die Gegend zu schieben und zeigen auf verschiedene Commits, während die Arbeit in ihnen fortschreitet. Ein Branch wird oft verändert, manchmal nur temporär, und ist ständig in Bewegung.",
"",
"Da das so ist fragst du dich vielleicht, ob es nicht eine Möglichkeit gibt, eine bestimmte Stelle in deiner Projekt-History *permanent* zu kennzeichnen. Kann man nicht zum Beispiel für große Releases und Meilensteine nicht einen Commit mit etwas festerem kennzeichnen, als mit einem Branch-Namen?",
""
@ -375,7 +487,7 @@
"Lass uns ein Tag bei `C1` anlegen und damit die Version 1 unseres Prototyps markieren."
],
"afterMarkdowns": [
"Peng! Ziemlich einfach. Wir haben das Tag `v1` genannt und lassen es auf `C1` zeigen. Wenn du den Commit weglässt wir das Tag für den Commit erzeugt, auf den `HEAD` zeigt."
"Peng! Ziemlich einfach. Wir haben das Tag `v1` genannt und lassen es auf `C1` zeigen. Wenn du den Commit weglässt, wird das Tag für den Commit erzeugt, auf den `HEAD` zeigt."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
@ -387,7 +499,7 @@
"markdowns": [
"Um diesen Level zu schaffen, erstelle einfach die Tags wie sie in der Zielbeschreibung stehen und mach dann einen Checkout auf `v1`. Beachte wie du dabei in den \"Detached HEAD\" Zustand gehst -- das liegt daran, dass du keine Commits direkt auf das `v1` Tag machen kannst.",
"",
"Im nächsten Level schauen wir uns dann interessantere Anwendungsfälle für Tags an."
"Im nächsten Level schauen wir uns dann einen interessanteren Anwendungsfall für Tags an."
]
}
}
@ -479,7 +591,7 @@
"Создадим тег на `C1`, который будет нашей версией 1"
],
"afterMarkdowns": [
"Готово! Всё просто. Мы назвали тег `v1` и заставили его ссылаться на `C1` явным образом. Если конкретный коммит не указан, гит пометит тегом `HEAD`"
"Готово! Всё просто. Мы назвали тег `v1` и заставили его ссылаться на `C1` явным образом. Если конкретный коммит не указан, гит пометит тегом `HEAD`."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
@ -505,7 +617,7 @@
"markdowns": [
"## Git 태그",
"",
"이전 강의에서 배웠듯이, 브랜치는 이동하기 쉽습니다. 작업의 완료, 진행에따라 이리저리 이동하면서 서로다른 커밋을 참조하게 됩니다. 브랜치는 쉽게 변하며 임시적인 것입니다 항상 바뀌고 있죠.",
"이전 강의에서 배웠듯이, 브랜치는 이동하기 쉽습니다. 작업의 완료, 진행에 따라 이리저리 이동하면서 서로 다른 커밋을 참조하게 됩니다. 브랜치는 쉽게 변하며 임시적인 것입니다 항상 바뀌고 있죠.",
"",
"이런 상황에서, 여러분은 여러분의 프로젝트의 역사(작업 이력)에서 중요한 지점들에 *영구적으로* 표시를 할 방법이 없을까 궁금할것입니다. 주요 릴리즈나 큰 브랜치 병합(merge)이 있을때가 그런 상황이겠군요. 이런 상황에 커밋들을 표시할 브랜치보다 영구적인 방법이 있을까요?",
""
@ -600,6 +712,110 @@
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Tag trong Git",
"",
"Qua các bài học trước, bạn đã biết được rằng rất dễ dàng để di chuyển qua lại giữa các nhánh và chúng thường tham chiếu đến các commit khác nhau trong quá trình ta làm việc trên chúng. Nhánh thường dễ biết đổi, thường chỉ là tạm thời và chúng luôn như vậy.",
"",
"Nếu như vậy thì bạn có thể sẽ thắc mắc liệu có cách nào để đánh dấu *vĩnh viễn* một thời điểm nào đó trong lịch sử làm việc không? Khi mà dự án càng ngày càng mở rộng và merge thì diễn ra liên tục, vậy thì có cách nào để đánh dấu những commit đó một cách cố định hơn nhánh không?",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Tất nhiên là có chứ! Git có các tag(thẻ) để hỗ trợ vấn đề này -- chúng (bằng cách nào đó) đánh dấu vĩnh viễn một commit cụ thể nào đó như một \"cột mốc\" mà sau đó bạn có thể tham chiếu đến như với nhánh.",
"",
"Quan trọng hơn là, khi ta commit thì chúng không hề bị di chuyển. Bạn không thể \"check out\" một tag rồi làm việc trên đó -- tag giống như là mỏ neo để chỉ định một điểm cụ thể nào dó trên cây lịch sử.",
"",
"Cùng xem tag thực tế là như thế nào nào."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Hãy thử tạo một thẻ ở commit `C1` chỉ định rằng đây là phiên bản thứ nhất của ta."
],
"afterMarkdowns": [
"Đó! Đơn giản như đan rổ. Ta tạo ra thẻ `v1` và tham chiếu đến commit `C1`. Nếu bạn không chỉ định commit, git sẽ gắn thẻ vào commit mà `HEAD` đang trỏ tới"
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Trong cấp độ này hãy tạo ra một thẻ tại vị trí chỉ định và chuyển sang `v1`. Để ý rằng bạn sẽ chuyến sang trạng thái tách biệt `HEAD` -- bởi vì bạn không thể tham chiếu đến thẻ `v1`.",
"",
"Sang cấp độ tới ta sẽ xem xét một vài cách hay ho để dùng thẻ."
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Tagi",
"",
"Kot si se naučil v prejšnjih lekcijah, so branchi enostavni za premikat okoli in pogosto kažejo na različne commite in delo za njimi. Veliko se spreminjajo in združujejo, pogosto le začasno.",
"",
"Če je temu res tako, se morda sprašuješ, če obstaja kak način, ki bi *trajno* označil točke v zgodovini projekta. Za stvari kot so večji release-i ali pomembni merge-i, ali obstaja način, ki je trajnejši kot branch?",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Itak da je! Git tagi podpirajo točno ta primer uporabe -- oni trajno (do neke mere) označijo določene commite kot \"mejnike\" na katere se lahko sklicujemo kot na branche.",
"",
"Toda še pomembneje, oni se ne premikajo, ko se ustvarjajo novi commiti. Ne moreš \"checkoutat\" tag in nato končati delo na tem tagu -- tagi obstajajo kot sidra na drevesu commitov, ki označujejo določene točke.",
"",
"Poglejmo kako to izgleda v praksi."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poizkusimo narediti tag na `C1`, ki je recimo naša prva različica prototipa."
],
"afterMarkdowns": [
"Tako! Kar enostavno. Tag smo poimenovali `v1` in se sklicuje na commit `C1`. Če ne navedeš commita, bo git postavil tag tam, kjer je trenutno `HEAD`."
],
"command": "git tag v1 C1",
"beforeCommand": "git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Za to stopnjo ustvari tage kot so določeni na ciljnem prikazu in nato checkoutaj `v1`. Opazil boš, kako prideš v stanje ločenega `HEAD-a` -- to je zato, ker ne moreš commitat direktno na `v1` tag.",
"",
"V naslednji stopnji si bomo pogledali zanimivejši primer za uporabo tagov."
]
}
}
]
}
}
};

View file

@ -1,4 +1,4 @@
exports.level = {
exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C7%27%22%2C%22id%22%3A%22master%22%7D%2C%22bugFix%22%3A%7B%22target%22%3A%22C3%22%2C%22id%22%3A%22bugFix%22%7D%2C%22side%22%3A%7B%22target%22%3A%22C5%22%2C%22id%22%3A%22side%22%7D%2C%22another%22%3A%7B%22target%22%3A%22C7%22%2C%22id%22%3A%22another%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C6%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C6%22%7D%2C%22C7%22%3A%7B%22parents%22%3A%5B%22C6%22%5D%2C%22id%22%3A%22C7%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C4%27%22%7D%2C%22C7%27%22%3A%7B%22parents%22%3A%5B%22C4%27%22%5D%2C%22id%22%3A%22C7%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git cherry-pick C3 C4 C7",
"compareOnlyMasterHashAgnostic": true,
@ -12,25 +12,35 @@
"de_DE": "Einführung Cherry-picking",
"ja" : "cherry-pick入門",
"es_AR": "Introducción a cherry-pick",
"es_ES": "Introducción a cherry-pick",
"pt_BR": "Introdução ao cherry-pick",
"gl" : "Introuducción a cherry-pick",
"zh_CN": "Git Cherry-pick",
"zh_TW": "介紹 cherry-pick",
"ru_RU": "Введение в Cherry-pick",
"ko" : "Cherry-pick 소개",
"uk": "Знайомство з cherry-pick"
"uk": "Знайомство з cherry-pick",
"vi" : "Giới thiệu về cherry-pick",
"sl_SI": "Uvod v Cherry-pick",
"pl": "Wprowadzenie do Cherry-pick'ingu"
},
"hint": {
"fr_FR": "git cherry-pick suivis par les noms de commits",
"fr_FR": "git cherry-pick suivi par les noms de commits",
"en_US": "git cherry-pick followed by commit names!",
"de_DE": "git cherry-pick gefolgt von Commit-Namen.",
"ja" : "git cherry-pickの後にコミット名を追加",
"es_AR": "git cherry-pick seguido de los nombres de los commits",
"es_ES": "git cherry-pick seguido de los nombres de los commits",
"pt_BR": "git cherry-pick seguido dos nomes dos commits",
"gl" : "git cherry-pick seguido das referencias a commits",
"zh_CN": "git cherry-pick 后面要跟提交的名字",
"zh_TW": "git cherry-pick 後面要接著 commit 的名稱",
"ru_RU": "git cherry-pick основывается на именах коммитов!",
"ko" : "커밋의 이름들로 git cherry-pick 하세요!",
"uk": "git cherry-pick базується на іменах комітів!"
"uk": "git cherry-pick базується на іменах комітів!",
"vi" : "git cherry-pick sau đó là tên commit!",
"sl_SI": "git cherry-pick nato pa imena commitov.",
"pl": "git cherry-pick a po nim nazwy commitów!",
},
"startDialog": {
"en_US": {
@ -70,20 +80,20 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Here's a repository where we have some work in branch `side` that we want to copy to `master`. This could be accomplished through a rebase (which we have already learned), but let's see how cherry-pick performs."
"Here's a repository where we have some work in branch `side` that we want to copy to `main`. This could be accomplished through a rebase (which we have already learned), but let's see how cherry-pick performs."
],
"afterMarkdowns": [
"That's it! We wanted commits `C2` and `C4` and git plopped them down right below us. Simple as that!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"To complete this level, simply copy some work from the three branches shown into master. You can see which commits we want by looking at the goal visualization.",
"To complete this level, simply copy some work from the three branches shown into main. You can see which commits we want by looking at the goal visualization.",
""
]
}
@ -127,20 +137,20 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Ici le dépôt que nous avons contient du travail dans la branche `side`, que nous voulons copier dans `master`. Cela pourrait être fait avec un rebase (que nous avons déjà appris), mais voyons comment cherry-pick fonctionne."
"Ici le dépôt que nous avons contient du travail dans la branche `side`, que nous voulons copier dans `main`. Cela pourrait être fait avec un rebase (que nous avons déjà appris), mais voyons comment cherry-pick fonctionne."
],
"afterMarkdowns": [
"Voilà ! Nous voulions les commits `C2` et `C4` et git les a fait apparaître juste sous nos jambes. Aussi simple que ça !"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Pour finir ce niveau, copiez simplement le travail désigné dans la branche master. Vous pouvez voir les commits que nous souhaitons avoir en regardant dans la fenêtre d'objectif.",
"Pour finir ce niveau, copiez simplement le travail désigné dans la branche main. Vous pouvez voir les commits que nous souhaitons avoir en regardant dans la fenêtre d'objectif.",
""
]
}
@ -171,7 +181,7 @@
"",
"El primer comando en esta serie se llama `git cherry-pick`. Tiene la siguiente forma:",
"",
"* `git cherry-pick <Commit1> <Commit2> <...>`",
" `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Es una manera bastante directa de decir que querés copiar una serie de commits sobre tu ubicación actual (`HEAD`). Personalmente amo `cherry-pick` porque hay muy poca magia involucrada y es bastante simple de entender.",
"",
@ -184,20 +194,77 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Acá tenemos un repositorio con algo de trabajo en la rama `side` que queremos copiar a `master`. Podríamos lograrlo con un rebase (y ya aprendimos cómo), pero veamos cómo se comporta cherry-pick."
"Acá tenemos un repositorio con algo de trabajo en la rama `side` que queremos copiar a `main`. Podríamos lograrlo con un rebase (y ya aprendimos cómo), pero veamos cómo se comporta cherry-pick."
],
"afterMarkdowns": [
"¡Eso es todo! Queríamos los commits `C2` y `C4` y git los aplicó justo donde estábamos. ¡Tan simple como eso!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, simplemente copiá algo de trabajo desde otras tres ramas a master. Podés ver qué commits queremos en la visualización del objetivo.",
"Para completar este nivel, simplemente copiá algo de trabajo desde otras tres ramas a main. Podés ver qué commits queremos en la visualización del objetivo.",
""
]
}
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Moviendo el trabajo por ahí",
"",
"Hasta ahora cubrimos lo básico de git -- hacer commits, crear ramas, y movernos por el árbol de commits. Estos conceptos alcanzan para aprovechar el 90% del poder de los repositorios de git y cubrir las necesidades principales de los desarrolladores.",
"",
"El 10% restante, sin embargo, puede ser bastante útil en flujos de trabajo complejos (o cuando te metiste en algún problema complicado). El próximo concepto que vamos a cubrir es el de \"mover el trabajo por ahí\" -- en otras palabras, una forma que tienen los desarrolladores de decir \"Quiero este trabajo aquí y este otro allí\" de una manera precisa, elocuente y flexible.",
"",
"Puede parecer un montón, pero es un concepto bastante simple."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Cherry-pick",
"",
"El primer comando en esta serie se llama `git cherry-pick`. Tiene la siguiente forma:",
"",
" `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Es una manera bastante directa de decir que quieres copiar una serie de commits sobre tu ubicación actual (`HEAD`). Personalmente amo `cherry-pick` porque hay muy poca magia involucrada y es bastante simple de entender.",
"",
"¡Veamos una demo!",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"A continuación tenemos un repositorio con algo de trabajo en la rama `side` que queremos copiar a `main`. Podríamos lograrlo con un rebase (y ya aprendimos cómo), pero veamos cómo se comporta cherry-pick."
],
"afterMarkdowns": [
"¡Eso es todo! Queríamos los commits `C2` y `C4` y git los aplicó justo donde estábamos. ¡Tan simple como eso!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, simplemente copia algo de trabajo desde otras tres ramas a main. Puedes ver qué commits queremos en la visualización del objetivo.",
""
]
}
@ -210,7 +277,7 @@
"type": "ModalAlert",
"options": {
"markdowns": [
"## Movendo trabalho por aí",
"## Movendo o trabalho por aí",
"",
"Por enquanto nós abordamos o básico do Git -- commitar, criar ramos, e mover-se pela árvore. Apenas esses conceitos já são suficientes para utilizar 90% do poder dos repositórios Git, e cobrem as principais necessidades dos desenvolvedores.",
"",
@ -241,20 +308,77 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Aqui está um repositório onde temos algum trabalho no ramo `side` que desejamos copiar para o `master`. Isso poderia ser obtido por meio de um rebase (que já aprendemos), mas vamos ver como o cherry-pick se sai."
"Aqui está um repositório onde temos algum trabalho no ramo `side` que desejamos copiar para o `main`. Isso poderia ser obtido por meio de um rebase (que já aprendemos), mas vamos ver como o cherry-pick se sai."
],
"afterMarkdowns": [
"É isso! Queríamos os commits `C2` e `C4` e o git os inseriu logo abaixo de nós. Simples assim!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nível, simplesmente copie algum trabalho dos outros três ramos para o master. Você pode ver quais commits queremos copiar na visualização do objetivo.",
"Para completar este nível, simplesmente copie algum trabalho dos outros três ramos para o main. Você pode ver quais commits queremos copiar na visualização do objetivo.",
""
]
}
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Movendo traballo por ahí",
"",
"Ata agora cubrimos o uso básico de git -- facer commit, crear ramas, e moverse pola árbore. Estes conceptos chegan para aproveitar o 90% do poder dos repositorios de git e cubrilas necesidades principais dos desenvolvedores.",
"",
"O 10% restante, ademáis, poden ser extremadamente útiles nos fluxos de traballo complexos (ou cando te meteches nalgún problema complicado). O próximo concepto que imos abordar é \"movendo o traballo por ahí\" -- noutras verbas, unha forma que teñen os desenvolvedores de dicir \"eu quero este traballo aquí, e aquel alí\" de forma precisa, elocuente e flexible.",
"",
"Eso pode ser moito, pero os conceptos son simples."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Cherry-pick",
"",
"O primeiro comando desta serie é `git cherry-pick`. O comando emprégase da seguinte forma:",
"",
"* `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Trátase dunha forma bastante directa de dicir que queres copiar unha serie de commits sobre a túa ubicación actual (`HEAD`). Eu persoalmente adoro `cherry-pick` porque hai moita maxia envolta e é un funcionamento sinxelo de entender.",
"",
"Vexamos unha demostración!",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Aquí está un repositorio onde hai algún traballo na rama `side` que desexamos copiar para a rama `main`. Iso podería ser obtido por medio dun rebase (que xa aprendemos), pero imos ver como o resolve cherry-pick."
],
"afterMarkdowns": [
"¡Eso é! Queríamos os commits `C2` e `C4` e git insertounos por baixo de nós. ¡Moi sinxelo!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, copia algo de traballo das outras ramas na main. Podes ver qué commits queremos copiar na visualización do obxectivo.",
""
]
}
@ -298,20 +422,20 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"這裡有一個 repo在 `side` branch 中,我們有一些 commit 想要複製到 `master` branch 上,這可以透過一個 rebase 來完成(我們之前已經學到了),但是讓我們看看 `git cherry-pick` 怎麼做。"
"這裡有一個 repo在 `side` branch 中,我們有一些 commit 想要複製到 `main` branch 上,這可以透過一個 rebase 來完成(我們之前已經學到了),但是讓我們看看 `git cherry-pick` 怎麼做。"
],
"afterMarkdowns": [
"就是那樣!我們複製了 `C2` 以及 `C4` 並且把它們放到我們的後面,很簡單吧!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"要完成這個關卡,只需要從三個 branch 複製幾個 commit 到 `master` 下面,你可以從視覺化的目標看到我們需要哪些 commit。",
"要完成這個關卡,只需要從三個 branch 複製幾個 commit 到 `main` 下面,你可以從視覺化的目標看到我們需要哪些 commit。",
""
]
}
@ -328,7 +452,7 @@
"",
"到现在我们已经学习了 Git 的基础知识 —— 提交、分支以及在提交树上移动。 这些概念涵盖了 Git 90% 的功能,同样也足够满足开发者的日常需求 ",
"",
"然而, 剩余的 10% 在处理复杂的工作流时(或者当你陷入困惑时)可能就显尤为重要了。接下来要讨论的这个话题是“整理提交记录” —— 开发人员有时会说“我想要把这个提交放到这里, 那个提交放到刚才那个提交的后面”, 而接下来就讲的就是它的实现方式,非常清晰、灵活,还很生动。",
"然而, 剩余的 10% 在处理复杂的工作流时(或者当你陷入困惑时)可能就显尤为重要了。接下来要讨论的这个话题是“整理提交记录” —— 开发人员有时会说“我想要把这个提交放到这里, 那个提交放到刚才那个提交的后面”, 而接下来就讲的就是它的实现方式,非常清晰、灵活,还很生动。",
"",
"看起来挺复杂, 其实是个很简单的概念。"
]
@ -354,20 +478,20 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"这里有一个仓库, 我们想将 `side` 分支上的工作复制到 `master` 分支,你立刻想到了之前学过的 `rebase` 了吧?但是咱们还是看看 `cherry-pick` 有什么本领吧。"
"这里有一个仓库, 我们想将 `side` 分支上的工作复制到 `main` 分支,你立刻想到了之前学过的 `rebase` 了吧?但是咱们还是看看 `cherry-pick` 有什么本领吧。"
],
"afterMarkdowns": [
"这就是了!我们只需要提交记录 `C2` 和 `C4`,所以 Git 就将被它们抓过来放到当前分支下了。 就是这么简单!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"要通过此关, 只需要简单的将三个分支中的提交记录复制到 master 上就可以了。目标窗口展示了我们想要哪些提交记录,如果你不小心关掉了的话,通过 `show goal` 命令可以打开,左上角也有“显示目标按钮”",
"要通过此关, 只需要简单的将三个分支中的提交记录复制到 main 上就可以了。目标窗口展示了我们想要哪些提交记录,如果你不小心关掉了的话,通过 `show goal` 命令可以打开,左上角也有“显示目标按钮”",
""
]
}
@ -382,7 +506,7 @@
"markdowns": [
"## Inhalte verschieben",
"",
"Bis jetzt haben wir uns die Grundlagen von Git angeschaut -- comitten, verzweigen und sich im Commit-Baum bewegen. Nur damit lässt sich schon 90% der Macht von Git-Repositories nutzen und die meisten Anforderungen von Entwicklern erfüllen.",
"Bis jetzt haben wir uns die Grundlagen von Git angeschaut -- comitten, verzweigen und sich im Commit-Baum bewegen. Nur damit lässt sich schon 90% der Macht von Git-Repositorys nutzen und die meisten Anforderungen von Entwicklern erfüllen.",
"",
"Die übrigen 10% jedoch können in komplexeren Abläufen sehr hilfreich sein (oder wenn man sich in eine schwierige Lage manövriert hat). Das nächste was wir uns anschauen, ist, Inhalte durch den Commit-Baum zu schieben. Es gibt dem Entwickler die Möglichkeit in präziser, eloquenter Manier zu sagen \"Ich will diese Inhalte hier und diese dort haben\".",
"",
@ -400,7 +524,7 @@
"",
"* `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Er ist eine einfache Möglichkeit um auszudrücken, dass du eine Folge von Commits unter deinen aktuellen Checkout (also `HEAD`) hängen möchtest. Ich persönlich liebe `cherry-pick`, weil es wenig Magic enthält und einfach zu verstehen ist.",
"Er ist eine einfache Möglichkeit um auszudrücken, dass du eine Folge von Commits unter deinen aktuellen Checkout (also `HEAD`) hängen möchtest. Ich persönlich liebe `cherry-pick`, weil es wenig Magie enthält und einfach zu verstehen ist.",
"",
"Schauen wir's uns mal an.",
""
@ -411,20 +535,20 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Hier haben wir ein Repository mit einigem Zeugs im Branch `side`, das wir in den Branch `master` kopieren wollen. Das könnten wir mit einem Rebase machen (wie bereits gesehen), aber schauen wir mal wie das mit `cherry-pick` geht."
"Hier haben wir ein Repository mit einigem Zeugs im Branch `side`, das wir in den Branch `main` kopieren wollen. Das könnten wir mit einem Rebase machen (wie bereits gesehen), aber schauen wir mal, wie das mit `cherry-pick` geht."
],
"afterMarkdowns": [
"Das war's! Wir wollten die commits `C2` und `C4` und Git hat die einfach unter unseren aktuellen Checkout kopiert. So einfach ist das."
"Das war's! Wir wollten die Commits `C2` und `C4` und Git hat die einfach unter unseren aktuellen Checkout kopiert. So einfach ist das."
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Um diesen Level zu schaffen musst du einfach nur einige Commits aus den drei gezeigten Branches in den `master` kopieren. Der Zielbaum zeigt dir, welche.",
"Um diesen Level zu schaffen musst du einfach nur einige Commits aus den drei gezeigten Branches in den `main` kopieren. Der Zielbaum zeigt dir, welche.",
""
]
}
@ -468,13 +592,13 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"このリポジトリには、現在`side`ブランチから`master`にコピーしたいコードがあります。この前に学んだrebaseコマンドでも実現可能ですが、ここではcherry-pickの動作を見ていきましょう。"
"このリポジトリには、現在`side`ブランチから`main`にコピーしたいコードがあります。この前に学んだrebaseコマンドでも実現可能ですが、ここではcherry-pickの動作を見ていきましょう。"
],
"afterMarkdowns": [
"これだけで終わりです!コミット`C2` と `C4`を取得したかったわけですが、gitが現在の位置の直下に落としてくれました。単純ですね"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
@ -525,13 +649,13 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Вот репозиторий, где есть некие изменения в ветке `side`, которые мы хотим применить и в ветку `master`. Мы можем сделать это при помощи команды rebase, которую мы уже прошли, но давай посмотрим, как cherry-pick справится с этой задачей."
"Вот репозиторий, где есть некие изменения в ветке `side`, которые мы хотим применить и в ветку `main`. Мы можем сделать это при помощи команды rebase, которую мы уже прошли, но давай посмотрим, как cherry-pick справится с этой задачей."
],
"afterMarkdowns": [
"Вуаля! Мы хотели перенести коммиты `C2` и `C4`, Git дал нам их там, где они нужны. Всё просто!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
@ -555,9 +679,9 @@
"",
"지금까지 우리는 git의 기초를 배웠습니다. -- 커밋을하고, 브랜치를 만들고, 소스 트리 여기저기를 돌아다녔습니다. 이런 개념들을 아는 것만으로도 git repository의 힘을 90%이상 사용하고 개발자들이 필요로하는 작업의 대부분을 할 수 있습니다.",
"",
"그 나머지 10% 기능이, 복잡한 작업(또는 작업중 막혔을때)중에 꽤 유용할 수 있습니다. 이제 배워 볼 다음 개념은 \"작업을 여기저로 기기\" 다시 말해, 개발자들의 언어로 \"이 일은 여기에 저 일은 저기에 두고 싶어\" 정확하고 우아하고 유연하게.",
"그 나머지 10% 기능이, 복잡한 작업(또는 작업중 막혔을때) 중에 꽤 유용할 수 있습니다. 이제 배워 볼 다음 개념은 \"작업을 여기저로 기기\" 다시 말해, 개발자들의 언어로 \"이 일은 여기에, 저 일은 저기에 두고 싶어\" 정확하고 우아하고 유연하게.",
"",
"다소 과해 보일 수 있는데, 간단한 개념입니다."
"다소 과해 보일 수 있지만, 간단한 개념입니다."
]
}
},
@ -582,20 +706,20 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"여기 repository가 있습니다. `master`와 master로 복사하고 싶은 작업이 있는 브랜치 `side`가 있습니다. 이것은 rebase를 통해서 할 수 있습니다(이미 배운), 하지만 체리-픽이 이 작업을 어떻게 수행하는지 확인해 봅시다."
"여기 repository가 있습니다. `main` 으로 복사하고 싶은 작업이 있는 브랜치 `side`가 있습니다. 이것은 rebase를 통해서 할 수 있습니다(이미 배운), 하지만 체리-픽이 이 작업을 어떻게 수행하는지 확인해 봅시다."
],
"afterMarkdowns": [
"됬습니다! 우리는 `C2`와 `C4` 커밋을 원했고 git이 우리가 원하는 곳 바로 밑에 톡 떨어뜨려 줬습니다. 아주 간단하죠!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"이 레벨을 통과하기 위해서는 몇개의 작업을 세개의 브랜치들에서 master로 복사해와야합니다. 어떤 커밋들이 필요한지는 goal을 보고 확인하면 됩니다.",
"이 레벨을 통과하기 위해서는 몇개의 작업을 세개의 브랜치들에서 `main` 브랜치로 복사해와야합니다. 어떤 커밋들이 필요한지는 goal을 보고 확인하면 됩니다.",
""
]
}
@ -639,25 +763,196 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Ми бачимо репозиторій де є певні зміни в гілці `side` які ми хочемо скопіювати в `master`. Для цього можна використати rebase (який ми вже вивчили), але подивимось як з цим впорається cherry-pick."
"Ми бачимо репозиторій де є певні зміни в гілці `side` які ми хочемо скопіювати в `main`. Для цього можна використати rebase (який ми вже вивчили), але подивимось як з цим впорається cherry-pick."
],
"afterMarkdowns": [
"Овва! Ми хотіли коміти `C2` та `C4` і git додав їх до поточного розташування. Просто й доступно!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout master; git commit;"
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Щоб пройти це рівень, просто скопіюй якісь зміни з трьох гілок показаних на діаграмі в master. В візуалізації видно які коміти потрібно скопіювати.",
"Щоб пройти це рівень, просто скопіюй якісь зміни з трьох гілок показаних на діаграмі в main. В візуалізації видно які коміти потрібно скопіювати.",
""
]
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Mang đi kéo về",
"",
"Cho đến giờ thì ta đã nắm được cơ bản về git -- commit, rẽ nhánh, và dịch chuyển qua lại trên cây mã nguồn. Chừng ấy khái niệm là đã đủ để tác động đến 90% sức mạnh của kho chứa git và các chức nawmg cần thiết cho nhà phát triển phần mềm.",
"",
"Tuy nhiên 10% còn lại thì lại khá hữu ích trong các quy trình làm việc phức tạp (hoặc khi bạn vướng phải tình huống khó khăn). The next concept we're going to cover is \"chỉnh lý các bản ghi\" -- đó là cách để nhà phát triển nói rằng\"Tôi muốn lấy bản ghi ở đây và cả bản ghi ở đó\" một cách chính xác, linh hoạt và sống động.",
"",
"Nghe thì có vẻ phức tạp, nhưng thực ra khái niệm này khá đơn giản."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Cherry-pick",
"",
"Lệnh đầu tiên của loạt bài này là `git cherry-pick`, dạng lệnh là::",
"",
"* `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Đó là cách rất trực tiếp để copy một loạt commit xuống dưới vị trí hiện tại của bạn (`HEAD`). Cá nhân tôi thì rất thích `cherry-pick` bởi tính tiện dụng và dễ hiểu của nó.",
"",
"Hãy xem qua một ví dụ!",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Ở đây ta có một kho chứa mà ta muốn sao chép thành quả công việc từ nhánh `side` sang nhánh `main`. Có thể dùng rebase để làm việc này (kỹ thuật mà ta đã học), nhưng hãy xem thử cherry-pick làm điều này ra sao."
],
"afterMarkdowns": [
"Thế thôi! Chúng ta chỉ cần các commit `C2` và` C4`, vì vậy Git sẽ lấy chúng và đặt chúng dưới nhánh hiện tại. Thật đơn giản!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Để hoàn thành cấp độ này, hãy copy thành quả công việc từ 3 nhánh khác vào main. Bạn có thể nhìn vào mô tả mục tiêu để biết chúng ta cần những commit nào.",
""
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Premikanje dela naokoli",
"",
"Zaenkrat smo pokrili osnove gita -- commitanje, branchanje in pomikanje po drevesu. Samo te koncepti so dovolj za koriščenje 90% moči git repozitorijev in pokrijejo večino potreb razvijalcev.",
"",
"Preostalih 10% pa je lahko kar uporabnih med reševanjem kompleksnejših situacij (ali ko ste zašli v zagato). Naslednji koncept, ki ga bomo pokrili je \"premikanje dela naokoli\" -- z drugimi besedami, tako razvijalci rečejo \"Rad bi to delo tu in tisto delo tam\" na natančen, zgovoren in prilagodljiv način.",
"",
"Morda se zdi veliko, a gre za preprost koncept."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Cherry-pick",
"",
"Prvi ukaz v zaporedju je `git cherry-pick`. Je sledeče oblike:",
"",
"* `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Gre za jasen način, da povemo, da bi radi skopirali zaporedje commitov pod trenutno lokacijo (`HEAD`). Sam imam rad `cherry-pick`, ker je vključeno le malo čarovnije in je preprost za razumet.",
"",
"Poglejmo predstavitev!",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Tu je repozitorij, kjer imamo nekaj dela na branchu `side`, ki bi ga radi skopirali na `main`. To bi lahko dosegli z rebase-om (kar smo se že naučili), ampak poglejmo kako se odreže cherry-pick."
],
"afterMarkdowns": [
"To je to! Želeli smo commita `C2` in `C4` in git ju je prilimal točno pod nas. Preprosto!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Za končanje te stopnje enostavno skopiraj nekaj dela iz predstavljenih treh branchev v main. V priloženi vizualizaciji lahko vidiš katere commite.",
""
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Przenoszenie pracy",
"",
"Do tej pory zajmowaliśmy się podstawami gita - commitowaniem, gałęziami i poruszaniem się w drzewie źródłowym. Tylko te koncepcje wystarczą, aby wykorzystać 90% mocy repozytoriów git i pokryć główne potrzeby deweloperów.",
"",
"Pozostałe 10% może być jednak dość użyteczne podczas niecodziennych zadań (lub gdy o czymś zapomniałeś). Kolejna koncepcja, którą zamierzamy omówić to \"przenoszenie pracy\" - innymi słowy, jest to sposób, w jaki deweloperzy mogą powiedzieć: \"Chcę te zmiany tu i tam\" w precyzyjny, wymowny i elastyczny sposób.",
"",
"To może wydawać się sporo, ale to prosta koncepcja."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Cherry-pick",
"",
"Pierwsza komenda w tej serii nazywa się `git cherry-pick`. Przyjmuje ona następującą formę:",
"",
"* `git cherry-pick <Commit1> <Commit2> <...>`",
"",
"Jest to bardzo prosty sposób określenia jakie zmiany poniżej swojej obecnej lokalizacji (`HEAD`) chciałbyś przenieść. Osobiście uwielbiam `cherry-pick'ing`, ponieważ jest to proste jak budowa cepa.",
"",
"Zobaczmy demo!",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Mamy tutaj repozytorium, gdzie mamy trochę pracy na gałęzi `side`, które chcemy skopiować do gałęzi `main`. Można by to osiągnąć dzięki komendy rebase'owi (którego już się nauczyliśmy), ale zobaczmy, jak działa cherry-pick."
],
"afterMarkdowns": [
"To jest to! Chcieliśmy aby commity `C2` i `C4` i git wziął i dodał do `main`. Bułka z masłem!"
],
"command": "git cherry-pick C2 C4",
"beforeCommand": "git checkout -b side; git commit; git commit; git commit; git checkout main; git commit;"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Aby ukończyć ten poziom, po prostu skopiuj część pracy z trzech pokazanych gałęzi `main`. Commity, które należy skopiować znajdują się na wizualizacji celu.",
""
]
}
}
]
},
}
};

View file

@ -1,32 +1,42 @@
exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C4\",\"id\":\"bugFix\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"}},\"HEAD\":{\"target\":\"C4\",\"id\":\"HEAD\"}}",
"solutionCommand": "git checkout C4",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C4\",\"id\":\"bugFix\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C2\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C4\",\"id\":\"bugFix\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"}},\"HEAD\":{\"target\":\"bugFix\",\"id\":\"HEAD\"}}",
"name": {
"en_US": "Detach yo' HEAD",
"es_AR": "Desatacheá tu HEAD",
"es_ES": "Desatachea tu HEAD",
"pt_BR": "Solte a sua cabeça",
"fr_FR": "Détachez votre HEAD",
"gl" : "Abandona o teu HEAD",
"fr_FR": "Détacher votre HEAD",
"zh_CN": "分离 HEAD",
"zh_TW": "分離 HEAD",
"de_DE": "Den Kopf abtrennen",
"ja" : "HEADの分離",
"ru_RU": "Теряем голову, или detached HEAD",
"ko" : "HEAD 분리하기",
"uk": "Втрачаємо голову чи detached HEAD"
"uk": "Втрачаємо голову чи detached HEAD",
'vi': "Tháo đầu cái nào",
"sl_SI": "Ločevanje tvoje glave - HEAD-a",
"pl" : "Odczep swój HEAD"
},
"hint": {
"en_US": "Use the label (hash) on the commit for help!",
"es_AR": "¡Usá la etiqueta (hash) sobre el commit para ayudarte!",
"es_ES": "¡Usa la etiqueta (hash) sobre el commit para ayudarte!",
"pt_BR": "Use o identificador (hash) sobre o commit para te ajudar!",
"gl" : "¡Usa a etiqueta (hash) sobre o commit para axudarte!",
"de_DE": "Benutze den Bezeichner (den Hash) des Commits.",
"ja" : "コミットのラベルhashを使用",
"fr_FR": "Utiiser le label (identifiant) du commit pour aider !",
"fr_FR": "Utilisez le label (identifiant) du commit pour aider !",
"zh_TW": "使用 commit 上的標籤hash來幫助你",
"zh_CN": "使用提交记录上的标签(哈希值)来指定提交记录!",
"ru_RU": "Ориентируйся по идентификаторам (hash) коммитов.",
"ko" : "커밋에 있는 라벨(hash)을 활용하세요!",
"uk": "Орієнтуйся по індентифікаторам (hash) комітів."
"uk": "Орієнтуйся по індентифікаторам (hash) комітів.",
"vi": "Dùng mã băm (hash) của commit để hoàn thành!",
"sl_SI": "Uporabi oznako (hash) commita za pomoč!",
"pl": "Wpisz (hash) w wiadomości commita aby uzyskać pomoc!",
},
"startDialog": {
"en_US": {
@ -69,9 +79,9 @@ exports.level = {
"Let's see this in action. Here we will reveal HEAD before and after a commit."
],
"afterMarkdowns": [
"See! HEAD was hiding underneath our `master` branch all along."
"See! HEAD was hiding underneath our `main` branch all along."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -83,7 +93,7 @@ exports.level = {
"",
"Detaching HEAD just means attaching it to a commit instead of a branch. This is what it looks like beforehand:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -144,12 +154,12 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamoslo en acción. Acá vamos a ver a HEAD antes y después de un commit."
"Veámoslo en acción. Acá vamos a ver a HEAD antes y después de un commit."
],
"afterMarkdowns": [
"¡Ves! HEAD estuvo oculta bajo nuestra rama `master` todo este tiempo."
"¡Ves! HEAD estuvo oculta bajo nuestra rama `main` todo este tiempo."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -161,7 +171,7 @@ exports.level = {
"",
"Detachear (_des-adjuntar_) HEAD simplemente significa adjuntarla a un commit en lugar de a un branch. Así es como se ve de antemano:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -177,7 +187,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, detacheemos HEAD de `bugFix` y ataccheemosla al commit, en cambio.",
"Para completar este nivel, detacheemos HEAD de `bugFix` y atacheemosla al commit, en cambio.",
"",
"Especificá este commit por su hash. El hash de cada commit se muestra en el círculo que lo representa."
]
@ -185,6 +195,84 @@ exports.level = {
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Moviéndote por ahí con Git",
"",
"Antes de meternos en algunas de las funcionalidades más avanzadas de git, es importante entender las distintas maneras de moverse por el árbol de commits que representa tu proyecto.",
"",
"Una vez que estés cómodo moviendote por ahí, tus poderes con los otros comandos de git ¡van a amplificarse!",
"",
"",
"",
"",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## HEAD",
"",
"Primero tenemos que hablar de \"HEAD\". HEAD es el nombre simbólico del commit sobre el que hemos hecho checkout -- es, básicamente, el commit sobre el que estás trabajando.",
"",
"HEAD siempre apunta al commit más reciente, reflejado en el árbol de commits. La mayoría de los comandos de git que hacen cambios al árbol de commits empiezan modificando HEAD.",
"",
"Normalmente HEAD apunta al nombre de una rama (como bugFix). Cuando creas un commit, el estado de bugFix se altera y este cambio es visible a través de HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veámoslo en acción. A continuación vamos a ver a HEAD antes y después de un commit."
],
"afterMarkdowns": [
"¡Ves! HEAD estuvo oculta bajo nuestra rama `main` todo este tiempo."
],
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"### Detacheando HEAD",
"",
"Detachear (_des-adjuntar_) HEAD simplemente significa adjuntarla a un commit en lugar de a un branch. Así es como se ve de antemano:",
"",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
"Y así queda ahora:",
"",
"HEAD -> C1"
],
"command": "git checkout C1",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, detaheemos HEAD de `bugFix` y atacheemosla al commit, en cambio.",
"",
"Especifica este commit por su hash. El hash de cada commit se muestra en el círculo que lo representa."
]
}
}
]
},
"pt_BR": {
"childViews": [
{
@ -225,9 +313,9 @@ exports.level = {
"Vejamos isto em ação. Aqui vamos mostrar o HEAD antes e depois de um commit."
],
"afterMarkdowns": [
"Veja! O HEAD estava se escondendo ao lado do nosso `master` esse tempo todo."
"Veja! O HEAD estava se escondendo ao lado do nosso `main` esse tempo todo."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -239,7 +327,7 @@ exports.level = {
"",
"Soltar o HEAD significa anexá-lo a um commit em vez de anexá-lo a um ramo. Antes do estado solto (\"detached\"), é assim como se parece:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -263,6 +351,84 @@ exports.level = {
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Movéndose en Git",
"",
"Antes de seguir con algunhas das funcionalidades máis avanzadas de Git, é importante entender as diferentes formas de se mover a través da árbore de commits que representa o teu proxecto.",
"",
"¡Unha vez que te sintas ben ó teu redor, os teus poderes empregando outros comandos de git serán amplificados!",
"",
"",
"",
"",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## HEAD",
"",
"Primeiro temos que falar sobre o \"commit actual\" (\"HEAD\"). HEAD é un nome simbólico para o commit atualmente ativo (o último checkout que se fixo) -- é esencialmente o commit sobre o cal estás traballando nese momento.",
"",
"O HEAD sempre apunta para o commit máis recentemente copiado sobre a árbore de traballo (arquivos do proxecto). A maioría dos comandos de git que fan algún cambio sobre a árbore de traballo empezarán movendo o HEAD.",
"",
"Normalmente o HEAD apunta para o nome dunha rama (por exemplo, bugFix). Quando fagas commit, o status do bugFix é alterado e ese cambio ocorre tamén sobre o HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Vexamos isto en acción. Aquí imos mostrar o HEAD antes e depois dun commit."
],
"afterMarkdowns": [
"Ves! O HEAD estivo ó lado do noso `main` todo este tempo."
],
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"### Soltando a cabeza",
"",
"Soltar o HEAD significa apuntar a un commit en vez de apuntar a unha rama. Antes do estado solo (\"detached\"), é así como aparece:",
"",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
"E agora é",
"",
"HEAD -> C1"
],
"command": "git checkout C1",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, imos soltar o HEAD de `bugFix` e en vez diso apuntamos ó commit.",
"",
"Especifica o commit por medio do hash correspondente. O hash de cada commit está dentro do círculo que representa ó commit (a letra C seguida dun número)."
]
}
}
]
},
"fr_FR": {
"childViews": [
{
@ -303,9 +469,9 @@ exports.level = {
"Voyons cela en action. Ici nous allons indiquer où se situe HEAD avant et après un commit."
],
"afterMarkdowns": [
"Vous voyez ! HEAD était caché en dessous de la branche `master` tout le long."
"Vous voyez ! HEAD était caché en dessous de la branche `main` tout le long."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -317,7 +483,7 @@ exports.level = {
"",
"Détacher HEAD signifie simplement que l'on attache HEAD à un commit au lieu d'une branche. Voilà à quoi cela ressemble actuellement :",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -349,7 +515,7 @@ exports.level = {
"markdowns": [
"## Navigation durch Git",
"",
"Bevor wir uns einige fortgeschrittene Konzepte in Git ansehen ist es wichtig, verschiedene Wege zum Navigieren durch den Commit-Baum, der das Projekt enthält, zu kennen.",
"Bevor wir uns einige fortgeschrittene Konzepte in Git ansehen, ist es wichtig, verschiedene Wege zum Navigieren durch den Commit-Baum, der das Projekt enthält, zu kennen.",
"",
"Sobald du das drauf hast, vergrößern sich deine Möglichkeiten in allen anderen Git-Befehlen.",
"",
@ -368,7 +534,7 @@ exports.level = {
"",
"Erst mal müssen wir über `HEAD` reden. `HEAD` ist ein Alias für den Commit, der gerade ausgecheckt ist -- es ist im Prinzip der Commit, an den du deinen nächsten Commit hängst.",
"",
"`HEAD` zeigt immer auf den neuesten Commit. Die meisten Git-Befehle, die den Baum verändern, fangen damit an dass sie `HEAD` verschieben.",
"`HEAD` zeigt immer auf den neuesten Commit. Die meisten Git-Befehle, die den Baum verändern, fangen damit an, dass sie `HEAD` verschieben.",
"",
"Normalerweise zeigt `HEAD` auf einen Branch-Namen (z.B. `bugFix`). Wenn du einen Commit machst, wird `bugFix` auf diesen Commit geschoben, und `HEAD` (da es auf `bugFix` zeigt) automatisch auch."
]
@ -381,9 +547,9 @@ exports.level = {
"Schauen wir uns das mal in Aktion an. Wir werden hier `HEAD` vor und nach dem Commit anzeigen."
],
"afterMarkdowns": [
"Siehst du? `HEAD` war die ganze Zeit unter `master` versteckt."
"Siehst du? `HEAD` war die ganze Zeit unter `main` versteckt."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -395,7 +561,7 @@ exports.level = {
"",
"`HEAD` abzukoppeln bedeutet, es direkt an einen bestimmten Commit zu hängen, anstatt an einen Branch. Wir gelangen dadurch in den \"detached HEAD state\". So sieht's vorher aus:",
"",
"`HEAD` -> `master` -> `C1`",
"`HEAD` -> `main` -> `C1`",
""
],
"afterMarkdowns": [
@ -455,12 +621,12 @@ exports.level = {
"下面咱们通过实际操作看一下。我们将会观察提交前后 HEAD 的位置。"
],
"afterMarkdowns": [
"看到了吗? HEAD 指向了 `master`,随着提交向前移动。",
"看到了吗? HEAD 指向了 `main`,随着提交向前移动。",
"",
"(译者注:实际这些命令并不是真的在查看 HEAD 指向,看下一屏就了解了。如果想看 HEAD 指向,可以通过 `cat .git/HEAD` 查看,",
"如果 HEAD 指向的是一个引用,还可以用 `git symbolic-ref HEAD` 查看它的指向。但是该程序不支持这两个命令)"
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -472,9 +638,9 @@ exports.level = {
"",
"分离的 HEAD 就是让其指向了某个具体的提交记录而不是分支名。在命令执行之前的状态如下所示: ",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
"",
"HEAD 指向 master master 指向 C1"
"HEAD 指向 main main 指向 C1"
],
"afterMarkdowns": [
"现在变成了",
@ -533,9 +699,9 @@ exports.level = {
"在實際的例子中。我們將會觀察 commit 前後 HEAD 的位置。"
],
"afterMarkdowns": [
"看吧HEAD 一直藏在 `master` 分支的後面。"
"看吧HEAD 一直藏在 `main` 分支的後面。"
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -547,7 +713,7 @@ exports.level = {
"",
"分離 HEAD 就是讓其指向一個 commit 而不是 branch 的名稱。這是指令執行之前的樣子:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -611,9 +777,9 @@ exports.level = {
"実際の動作を見てみましょう。ここでは、コミットの前と後のHEADの状態を確認します。"
],
"afterMarkdowns": [
"ほら、HEADが元から`master`ブランチの下に隠れていたんですね!"
"ほら、HEADが元から`main`ブランチの下に隠れていたんですね!"
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -625,7 +791,7 @@ exports.level = {
"",
"HEADの分離(detached HEAD)とは単に、ブランチではなく特定のコミットにHEADを紐づけることです。実行前の状態は次のようです:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -689,9 +855,9 @@ exports.level = {
"Посмотрим, как это работает. Обратите внимание на то, где находится HEAD до и после коммита."
],
"afterMarkdowns": [
"Вот! HEAD всё это время скрывался за веткой `master`."
"Вот! HEAD всё это время скрывался за веткой `main`."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -703,7 +869,7 @@ exports.level = {
"",
"Отделение (detaching) HEAD означает лишь присвоение его не ветке, а конкретному коммиту. Посмотрим, что было до отделения:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -767,9 +933,9 @@ exports.level = {
"직접 확인해 봅시다. 여기서 우리는 보이지 않던 HEAD를 커밋전, 후에 드러낼 것입니다."
],
"afterMarkdowns": [
"보세요! HEAD가 `master`브랜치 아래에 숨어 있던 거군요."
"보세요! HEAD가 `main`브랜치 아래에 숨어 있던 거군요."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -781,7 +947,7 @@ exports.level = {
"",
"HEAD를 분리한다는 것은 HEAD를 브랜치 대신 커밋에 붙이는 것을 의미합니다. 명령을 사용하기 전의 모습은 다음과 같습니다:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -845,9 +1011,9 @@ exports.level = {
"Розберемось з цим на практиці. Зараз ми перевіримо HEAD до та після коміту."
],
"afterMarkdowns": [
"Ти диви! HEAD весь цей час ховався за гілкою `master`."
"Ти диви! HEAD весь цей час ховався за гілкою `main`."
],
"command": "git checkout C1; git checkout master; git commit; git checkout C2",
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
@ -859,7 +1025,7 @@ exports.level = {
"",
"Detached HEAD (відокремлена голова) просто означає що HEAD посилається на коміт, а не на якусь гілку. Ось як це виглядає спочатку:",
"",
"HEAD -> master -> C1",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
@ -882,6 +1048,240 @@ exports.level = {
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Dịch chuyển trong Git",
"",
"Trước khi học thêm vài chức năng nâng cao trong Git, ta cần phải biết cách dịch chuyển qua lại các commit có trong kho chứa.",
"",
"Một khi bạn đã thành thao với chuyển dịch, khả năng sử dụng các lệnh git của bạn đã được nâng cao!",
"",
"",
"",
"",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## HEAD",
"",
"Đầu tiên hãy bàn về 'HEAD'. HEAD là cái tên biểu tượng cho commit iện tại đang được trỏ đến -- về căn bản nó là commit mà bạn đang làm việc.",
"",
"HEAD luôn luôn trỏ đến commit gần nhất được phản ánh trong cây làm việc. Hầu hết các lệnh git mà làm thay đổi nội dung cây làm việc thường bắt đầu với HEAD.",
"",
"Bình thường HEAD thì trỏ tới tên nhánh (ví dụ bugFix). Khi bạn commit, thì trạng thái của bugFix được thay đổi và thay đổi này được trông thấy thông qua HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Xem thử thực tế nào. Ở đây ta sẽ bộc lộ HEAD trước và sau khi commit."
],
"afterMarkdowns": [
"Thấy chứ? HEAD đã ẩn dưới nhánh `main` suốt."
],
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"### Tháo HEAD",
"",
"Tháo HEAD đơng giản nghĩa là dán nó vào một commit thay vì một nhánh. Lúc trước thì nó trông như thế này:",
"",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
"Và bây giờ thì nó thế này",
"",
"HEAD -> C1"
],
"command": "git checkout C1",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Để hoàn thành cấp độ này, hãy tháo HEAD khỏi `bugFix` thay vì đó hãy dán nó vào commit.",
"",
"Chỉ rõ commit bằng mã băm (hash) của nó. Mã băm của mỗi commit nằm trong trong vòng tròn biểu thị commit đó."
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Premikanje po Gitu",
"",
"Preden se lotimo nekaj naprednejših funkcij Gita je pomembno, da razumemo različne načine premikanja po drevesu commitov, ki predstavljajo tvoj projekt.",
"",
"Ko ti je enkrat premikanje po drevesu domače, bodo tvoje sposobnosti z ostalimi git ukazi še močnejše!",
"",
"",
"",
"",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## HEAD",
"",
"Najprej moramo spozanti \"HEAD\". HEAD (glava) je simbolično ime za trenutno checkoutan commit -- v bistvu povemo na katerem commitom bomo nadaljevali.",
"",
"HEAD vedno kaže na zadnji commit na trenutnem drevesu. Večina git ukazov, ki spreminjajo to delovno drevo, bo začelo s spremembo HEAD-a.",
"",
"Ponavadi HEAD kaže na ime brancha (npr. bugFix). Ko commitaš, je stanje bugFix spremenjeno in ta sprememba je opazna tudi skozi HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poglejmo to v akciji. Sedaj bomo razkrili HEAD pred in po commitu."
],
"afterMarkdowns": [
"Evo! HEAD se je vseskozi skrival pod našim `main` branchom."
],
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"### Ločevanje HEAD-a",
"",
"Ločevanje HEAD-a pomeni samo, da ga namestno na branch sedaj pripnemo na commit. Tako je izgledalo prej:",
"",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
"Sedaj pa je takole:",
"",
"HEAD -> C1"
],
"command": "git checkout C1",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Za dokončanje te stopnje odstranimo HEAD iz `bugFix` in ga pritrdimo raje na commit.",
"",
"Določi ta commit z njegovim hash-om. Hash za vsak commit je predstavljen v krogu, ki predstavlja commit."
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Poruszanie się w Git",
"",
"Zanim przejdziemy do niektórych z bardziej zaawansowanych funkcji Gita, ważne jest, aby zrozumieć różne sposoby poruszania się po drzewie commitów, które reprezentują twój projekt.",
"",
"Kiedy będziesz już czuć się swobodnie, twoje moce z innymi komendami gitowymi zostaną wzmocnione!",
"",
"",
"",
"",
""
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## HEAD",
"",
"Najpierw musimy porozmawiać o \"HEAD\". HEAD to symboliczna nazwa dla aktualnie zcheckout'owanego commitu - jest to zasadniczo ostatni commit nad, którym pracowałeś.",
"",
"HEAD zawsze wskazuje na najnowszy commit, który jest odzwierciedlony w drzewie zmian. Większość poleceń git, które wprowadzają zmiany w drzewie, zaczyna się od zmiany HEAD'a.",
"",
"Normalnie HEAD wskazuje na nazwę gałęzi (jak np. `bugFix`). Kiedy commitujesz zmiany, status gałęzi `bugFix` się zmienia i zmiana ta jest widoczna właśnie poprzez przemieszczenie się HEAD'a."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Sprawdźmy to w akcji. Pokażemy HEAD przed i po commicie."
],
"afterMarkdowns": [
"Zobacz! HEAD przez cały czas ukrywał się pod naszą gałęzią `main`."
],
"command": "git checkout C1; git checkout main; git commit; git checkout C2",
"beforeCommand": ""
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"### Odłączanie HEAD'a",
"",
"Odłączenie HEAD'a oznacza po prostu dołączenie go do commita, a nie gałęzi. Tak to wyglądało przed:",
"",
"HEAD -> main -> C1",
""
],
"afterMarkdowns": [
"A tak po:",
"",
"HEAD -> C1"
],
"command": "git checkout C1",
"beforeCommand": ""
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Aby ukończyć ten poziom, odłącz HEAD od gałęzi `bugFix` i dołącz go do commita.",
"",
"Możesz wybrać konkretnego commita posługując się jego haszem. Hasz każdego commita jest wyświetlany na okręgu, który go reprezentuje."
]
}
}
]
}
}
};

View file

@ -1,4 +1,4 @@
exports.level = {
exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C4%27%22%2C%22id%22%3A%22master%22%7D%2C%22overHere%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22overHere%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%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C4%22%3A%7B%22parents%22%3A%5B%22C3%22%5D%2C%22id%22%3A%22C4%22%7D%2C%22C5%22%3A%7B%22parents%22%3A%5B%22C4%22%5D%2C%22id%22%3A%22C5%22%7D%2C%22C3%27%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%27%22%7D%2C%22C5%27%22%3A%7B%22parents%22%3A%5B%22C3%27%22%5D%2C%22id%22%3A%22C5%27%22%7D%2C%22C4%27%22%3A%7B%22parents%22%3A%5B%22C5%27%22%5D%2C%22id%22%3A%22C4%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22master%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git rebase -i overHere --solution-ordering C3,C5,C4",
"compareOnlyMasterHashAgnostic": true,
@ -9,20 +9,27 @@
"hint": {
"en_US": "you can use either branches or relative refs (HEAD~) to specify the rebase target",
"es_AR": "podés usar tanto ramas como referencias relativas (HEAD~) para especificar el objetivo del rebase",
"es_ES": "puedes usar tanto ramas como referencias relativas (HEAD~) para especificar el objetivo del rebase",
"pt_BR": "Você pode usar ou ramos ou referências relativas (HEAD~) para especificar o alvo do rebase",
"gl" : "Podes usar ramas ou referencias relativas (HEAD~) para especificar o obxectivo do rebase",
"de_DE": "Du kannst entweder Branches oder relative Ref-Angaben (z.B. HEAD~) benutzen, um das Ziel des Rebase anzugeben.",
"fr_FR": "Vous pouvez utiliser soit les branches, soit les références relatives (HEAD~) pour spéficier la cible à rebaser",
"fr_FR": "Vous pouvez utiliser soit les branches, soit les références relatives (HEAD~) pour spécifier la cible à rebaser",
"zh_CN": "branch 或者是相对位置HEAD~)都可以用來指定 rebase 的目标",
"zh_TW": "你可以指定 branch 或者是相對位置HEAD~)來表示 rebase 的目標",
"ru_RU": "Можно использовать либо ветки, либо относительные ссылки (HEAD~), чтобы указать цель для Rebase",
"ja" : "リベースする対象の指定には、ブランチ名や相対リファレンス(HEAD~)が使えます",
"ko" : "리베이스할 타겟으로 브랜치나 상대 참조(HEAD~)를 사용할 수 있습니다",
"uk" : "ти можеш використовувати гілки чи відносні посилання (HEAD~) щоб вказувати ціль для rebase"
"uk" : "ти можеш використовувати гілки чи відносні посилання (HEAD~) щоб вказувати ціль для rebase",
"vi": "bạn có thể sử dụng tham chiếu tương đối (HEAD~) hoặc nhánh để chỉ định mục tiêu rebase",
"sl_SI": "Uporabiš lahko bilokateri branch ali relativno referenco (HEAD~), da določiš cilj za rebase.",
"pl": "Możesz użyć gałęzi lub referencji względnych (HEAD~), aby określić cel rebase'a"
},
"name": {
"en_US": "Interactive Rebase Intro",
"es_AR": "Introducción al rebase interactivo",
"es_ES": "Introducción al rebase interactivo",
"pt_BR": "Introdução ao rebase interativo",
"gl" : "Introducción ó rebase interativo",
"de_DE": "Einführung Interactive Rebase",
"ja" : "インタラクティブrebase入門",
"fr_FR": "Introduction à rebase",
@ -30,7 +37,10 @@
"zh_TW": "介紹互動式的 rebase",
"ru_RU": "Введение в интерактивный Rebase",
"ko" : "인터랙티브 리베이스 소개",
"uk" : "Знайомство з інтерактивним rebase"
"uk" : "Знайомство з інтерактивним rebase",
"vi" : "Giới thiệu về tương tác rebase",
"sl_SI": "Interaktivni uvod v Rebase",
"pl": "Interaktywne wprowadzenie do Rebase'a",
},
"startDialog": {
"en_US": {
@ -65,11 +75,14 @@
"type": "ModalAlert",
"options": {
"markdowns": [
"When the interactive rebase dialog opens, you have the ability to do 3 things:",
"When the interactive rebase dialog opens, you have the ability to do two things in our educational application:",
"",
"* You can reorder commits simply by changing their order in the UI (in our window this means dragging and dropping with the mouse).",
"* You can choose to completely omit some commits. This is designated by `pick` -- toggling `pick` off means you want to drop the commit.",
"* Lastly, you can squash commits. Unfortunately our levels don't support this for a few logistical reasons, so I'll skip over the details of this. Long story short, though -- it allows you to combine commits.",
"* You can reorder commits simply by changing their order in the UI (via dragging and dropping with the mouse).",
"* You can choose to keep all commits or drop specific ones. When the dialog opens, each commit is set to be included by the `pick` " +
"button next to it being active. To drop a commit, toggle off its `pick` button.",
"",
"*It is worth mentioning that in the real git interactive rebase you can do many more things like squashing (combining) commits, " +
"amending commit messages, and even editing the commits themselves. For our purposes though we will focus on these two operations above.*",
"",
"Great! Let's see an example."
]
@ -82,7 +95,7 @@
"When you hit the button, an interactive rebase window will appear. Reorder some commits around (or feel free to unpick some) and see the result!"
],
"afterMarkdowns": [
"Boom! Git copied down commits in the exact same way you specified through the UI"
"Boom! Git copied down commits in the exact same way you specified through the UI."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
@ -108,7 +121,7 @@
"",
"Git cherry-pick est pratique quand vous savez exactement quels commits vous voulez (_et_ que vous connaissez leurs identifiants) -- il est difficile de battre la simplicité qu'il procure.",
"",
"Mais que faire quand vous ne connaissez pas les identifiants des commits ? Heureusement git a pensé à vous dans pour ce cas-là ! Nous pouvons utiliser un rebase interactif pour cela -- c'est la meilleure façon de reconsidérer une série de commits que vous vous apprêtez à rebaser.",
"Mais que faire quand vous ne connaissez pas les identifiants des commits ? Heureusement git a pensé à vous pour ce cas-là ! Nous pouvons utiliser un rebase interactif pour cela -- c'est la meilleure façon de reconsidérer une série de commits que vous vous apprêtez à rebaser.",
"",
"Allons un peu plus dans les détails ..."
]
@ -236,7 +249,7 @@
"markdowns": [
"## 交互式的 rebase",
"",
"当你知道你所需要的提交记录(**并且**还知道这些提交记录的哈希值)时, 用 cherry-pick 再好不过了 —— 没有比这更简单的方式了。",
"当你知道你所需要的提交记录(**并且**还知道这些提交记录的哈希值)时, 用 cherry-pick 再好不过了 —— 没有比这更简单的方式了。",
"",
"但是如果你不清楚你想要的提交记录的哈希值呢? 幸好 Git 帮你想到了这一点, 我们可以利用交互式的 rebase —— 如果你想从一系列的提交记录中找到想要的记录, 这就是最好的方法了",
"",
@ -317,7 +330,7 @@
"",
"Si incluís esta opción, git abrirá una UI para mostrarte qué commits están a punto de ser copiados sobre el objetivo del rebase. También muestra sus hashes y mensajes, que ayuda mucho para saber qué es cada commit.",
"",
"Para el git \"de verdad\", la UI signfica abrir un archivo en un editor de textos como `vim`. Para nuestro propósito, hice una pequeña interfaz que se comporta de ese mismo modo."
"Para el git \"de verdad\", la UI significa abrir un archivo en un editor de textos como `vim`. Para nuestro propósito, hice una pequeña interfaz que se comporta de ese mismo modo."
]
}
},
@ -342,7 +355,7 @@
"Cuando apretes el botón, va a aparecer una ventana de rebase interactivo. Reordená los commits (sentite libre de ignorar alguno, también) ¡y mirá el resultado!"
],
"afterMarkdowns": [
"¡Boom! Git copió los commits exactamente de la misma manera que lo especificaste en la UI"
"¡Boom! Git copió los commits exactamente de la misma manera que lo especificaste en la UI."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
@ -358,6 +371,71 @@
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## git rebase interactivo",
"",
"git cherry-pick es genial cuando sabes qué commits quieres (_y_ sabes sus hashes) -- es dificil superar la simpleza que provee.",
"",
"Pero ¿qué pasa cuando no sabes qué commits quieres? Por suerte ¡git te cubre en esta situación, también! Podemos usar el rebase interactivo para esto -- es la mejor manera de revisar una serie de commits que estás a punto de rebasear.",
"",
"Entremos en los detalles..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Todo rebase interactivo significa usar el comando `rebase` con la opción `-i`.",
"",
"Si incluyes esta opción, git abrirá una UI para mostrarte qué commits están a punto de ser copiados sobre el objetivo del rebase. También muestra sus hashes y mensajes, que ayuda mucho para saber qué es cada commit.",
"",
"Para el git \"de verdad\", la UI signfica abrir un archivo en un editor de textos como `vim`. Para nuestro propósito, hice una pequeña interfaz que se comporta de ese mismo modo."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Cuando el diálogo de rebase interactivo se abre, tienes la capacidad de hacer 3 cosas:",
"",
"* Puedes reordenar los commits con solamente cambiar su orden en la UI (en nuestra ventana, eso significa hacer drag & drop con el mouse).",
"* Puedes elegir ignorar completamente algunos commits. Esto se designa con `pick` -- no hacerle `pick` a algún commit significa que quieres ignorarlo.",
"* Finalmente, puedes _squashear_ commits. Desafortunadamente, nuestros niveles no soportan esto por cuestiones logísticas, por lo que voy a ahorrarte los detalles. Resumiendo, te permite combinar varios commits en uno solo.",
"",
"¡Genial! Veamos un ejemplo."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Cuando aprietes el botón, va a aparecer una ventana de rebase interactivo. Reordena los commits (siéntete libre de ignorar alguno, también) ¡y observa el resultado!"
],
"afterMarkdowns": [
"¡Zas! Git copió los commits exactamente de la misma manera que lo especificaste en la UI."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar el nivel, haz un rebase interactivo y alcanza el orden que se muestra en la visualización objetivo. Recuerda que siempre puedes hacer `undo` y `reset` para arreglar errores :D"
]
}
}
]
},
"pt_BR": {
"childViews": [
{
@ -407,7 +485,7 @@
"Quando você clicar o botão, uma janela de rebase interativo se abrirá. Reordene alguns commits da forma como você preferir (ou sinta-se livre para desmarcar o `pick` de alguns) e veja o resultado!"
],
"afterMarkdowns": [
"Boom! O Git copiou alguns commits exatamente da mesma forma que você os especificou na janela"
"Boom! O Git copiou alguns commits exatamente da mesma forma que você os especificou na janela."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
@ -423,6 +501,71 @@
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Rebase Interativo en Git",
"",
"Empregar cherry-pick é xenial cando coñeces qué commits queres (_e_ coñeces os seus códigos hash) -- é difícil mellorar a súa simplicidade.",
"",
"Pero ¿qué pasa cando non sabes qué commits son os que queres? Por sorte, ¡git cúbrete nesta situación tamén! Podemos empregar o rebase interactivo para esto -- é a mellor forma de revisar unha serie de commits que estás a rebasar.",
"",
"Mergullémonos nos detalles..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"O rebase interativo é o comando `rebase` coa opción `-i`.",
"",
"Se ti inclúes esta opción, o git abrirá unha interfaz para mostrar qué commits están hábiles para ser copiados sobre o obxectivo do rebase. Tamén amosa os seus códigos hash e mensaxes dos commits, o cal axuda moito para saber qué é cada commit.",
"",
"En git \"de verdade\", a interfaz significa abrir un arquivo de texto nun editor (por exemplo `vim`). Para os nosos propósitos, aquí aparecerá unha pequena ventá que se comporta do mesmo xeito."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Cando a xanela de rebase interativo abra, poderás facer 3 cousas distintas:",
"",
"* Podes reordenar os commits simplemente cambiando a súa orde na interface (na nosa ventá significa arrastrar e soltar os commits).",
"* Podes escoller a opción de omitir algúns commits. Para iso, pincha no botón `pick` -- deixar o `pick` desligado significa que queres descartar o commit.",
"* Ademáis, ti podes \"esmagar\" (fazer squash) nos commits. Tristemente, este tutorial non será capaz de cubrir esa funcionalidade por algúns motivos loxísticos, entón imos pulir algúns detalles ó respecto. Resumindo, o squash permite combinar commits.",
"",
"¡Xenial! Vexamos un exemplo."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Cando pinches o botón, unha ventá de rebase interativo abrirase. Reordena algúns commits da forma que ti prefieras (ou se o prefires desmarca o `pick` de algúns) e mira o seu resultado!"
],
"afterMarkdowns": [
"¡Veña! Git copiou algúns commits exatamente da mesma forma que o indicaches na ventá."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para finalizar este nivel, fai un rebase interativo e obteñaa a orde amosada na visualización do obxectivo. Lembra que podes usar os comandos `undo` ou `reset` para correxir erros :D"
]
}
}
]
},
"de_DE": {
"childViews": [
{
@ -431,9 +574,9 @@
"markdowns": [
"## Interaktiver Rebase",
"",
"Cherry-pick ist großartig wenn du genau weißt, welche Commits du willst (_und_ ihre jeweiligen Hashes kennst) -- es ist dann schwer an Einfachheit zu überbieten.",
"Cherry-pick ist großartig, wenn du genau weißt, welche Commits du willst (_und_ ihre jeweiligen Hashes kennst) -- es ist dann schwer an Einfachheit zu überbieten.",
"",
"Aber wie sieht es aus, wenn du die Commits nicht genau kennst, die du brauchst? Zum Glück bietet Git auch dafür eine Lösung an. Das können wir mit interaktivem Rebase machen -- die beste Art sich eine Serie von Commits in einem Rebase genau anzusehen.",
"Aber wie sieht es aus, wenn du die benötigten Commits nicht genau kennst? Zum Glück bietet Git auch dafür eine Lösung an. Das können wir mit interaktivem Rebase machen -- die beste Art sich eine Serie von Commits in einem Rebase genau anzusehen.",
"",
"Schauen wir uns die Details an ..."
]
@ -447,7 +590,7 @@
"",
"Wenn du das machst, zeigt Git dir jeden einzelnen Commit, der durch den Rebase kopiert werden würde. Es zeigt dir die Hashes und Kommentare, was gut ist um einen Überblick zu bekommen.",
"",
"In echtem Git besteht dieser Dialog daraus, die Commits in einem Text-Editor angezeigt zu bekommen. Für unsere Zwecke hab ich ein kleines Dialog-Fenster gebaut, dass sich ähnlich verhält."
"Im \"echten\" Git werden die Commits in einem Text-Editor angezeigt (z.B. in `vim`). Für unsere Zwecke habe ich ein kleines Dialog-Fenster gebaut, das sich ähnlich verhält."
]
}
},
@ -458,8 +601,8 @@
"Wenn sich der Dialog für den interaktiven Rebase öffnet, kannst du drei Dinge tun:",
"",
"* Du kannst die Reihenfolge der Commits durch Ziehen und Ablegen ändern.",
"* Du kannst Git sagen, einen Commit beim Rebase zu ignorieren -- im Dialog durch die Schaltfläche `pick` dargestellt.",
"* Außerdem kannst du Commit zusammenfassen (squash). Leider wird das hier nicht unterstützt, aber in echtem Git fasst es Commits zu einem zusammen.",
"* Du kannst einen Commit beim Rebase ignorieren, indem du im Dialog auf die Schaltfläche `omit` klickst. Du kannst einen Commit wieder aufnehmen, indem du auf `pick` klickst.",
"* Außerdem kannst du Commits zusammenfassen (squash). Leider wird das hier nicht unterstützt, aber im echten Git fasst es Commits zu einem zusammen.",
"",
"Super! Schauen wir uns ein Beispiel an."
]
@ -469,7 +612,7 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Wenn du die Schaltfläche anklickst wird sich der Rebase-Dialog öffnen. Veränder die Reihenfolge der Commits oder klick bei einigen auf `pick` und schau dir das Ergebnis an."
"Wenn du die Schaltfläche anklickst, wird sich der Rebase-Dialog öffnen. Verändere die Reihenfolge der Commits oder klicke bei einigen auf `pick` bzw. `omit` und schaue dir das Ergebnis an."
],
"afterMarkdowns": [
"Bämm! Git hat die Commits genau so kopiert, wie du es ausgewählt hast."
@ -482,7 +625,7 @@
"type": "ModalAlert",
"options": {
"markdowns": [
"Um dieses Level zu schaffen mach einen interaktiven Rebase, um genau die Reihenfolge zu erzeugen die im Ziel-Baum angezeigt wird. Denk daran, dass du jederzeit mit `undo` oder `reset` Fehler rückgängig machen kannst. :D"
"Um dieses Level zu schaffen mach einen interaktiven Rebase, um genau die Reihenfolge zu erzeugen, die im Ziel-Baum angezeigt wird. Denk daran, dass du jederzeit mit `undo` oder `reset` Fehler rückgängig machen kannst. :D"
]
}
}
@ -642,7 +785,7 @@
"",
"이 옵션을 추가하면, git은 리베이스의 목적지가 되는 곳 아래에 복사될 커밋들을 보여주는 UI를 띄울것 입니다. 각 커밋을 구분할 수 있는 각각의 해시들과 메시지도 보여줍니다.",
"",
"\"실제\"git 에서는 UI창을 띄우는것 대신에 `vim`과 같은 텍스트 편집기에서 파일을 엽니다. 저희는 배우는것이 목적이기에 같은 역할을 하는 작은 대화창을 만들어서 대신했습니다."
"\"실제\" git 에서는 UI창을 띄우는것 대신에 `vim`과 같은 텍스트 편집기에서 파일을 엽니다. 저희는 배우는 것이 목적이기에 같은 역할을 하는 작은 대화창을 만들어서 대신했습니다."
]
}
},
@ -664,7 +807,7 @@
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"버튼을 누르면 인터렉티브 리베이스 대화창이 뜰것 입니다. 커밋들의 순서를 바꿔보고(커밋을 빼 봐도 됩니다) 결과를 확인해봅시다!"
"버튼을 누르면 인터렉티브 리베이스 대화창이 뜰 것 입니다. 커밋들의 순서를 바꿔보고(커밋을 빼 봐도 됩니다) 결과를 확인해봅시다!"
],
"afterMarkdowns": [
"Boom! Git이 UI를 통해 명시한 그대로 커밋들을 복사했습니다."
@ -732,7 +875,7 @@
"Коли ти натиснеш кнопку, відкриється вікно інтерактивного rebase. Перестав якісь коміти (можеш пропустити якісь якщо хочеш), і подивись що вийде!"
],
"afterMarkdowns": [
"Ка-бум! Git cкопіював коміти відповідно до того що було вказано в UI"
"Ка-бум! Git cкопіював коміти відповідно до того що було вказано в UI."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
@ -747,6 +890,202 @@
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Rebase Tương tác",
"",
"Khi bạn biết rõ mình muốn những commit nào (và mã băm tương ứng của chúng) thì Git cherry-pick là công cụ tuyệt vời -- nó đơn giản đến bất ngờ.",
"",
"Nhưng mà lỡ như bạn không biết mình cần commit nào thì sao? May mà git cũng có công cụ cho việc này! Ta có thể dùng rebase tương tác cho việc này -- đó là cách tốt nhất để cân nhắc lựa chọn các commit mà bạn muốn rebase.",
"",
"Hãy đi sâu vào chi tiết nào..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Rebase tương tác nghĩa là dùng lệnh `rebase` với tùy chọn `-i`.",
"",
"Nếu lệnh của bạn có bao hàm tùy chọn này, git sẽ mở một giao diện người dùng để cho bạn biết những commit nào sẽ được sao chép xuống dưới mục tiêu rebase. Nó cũng đồng thời thể hiện mã băm và thông điệp của commit, điều này là tuyệt vời bởi nhờ đó ta có thể phân biệt được chúng.",
"",
"Với git \"thật\", cửa sổ UI (giao diện người dùng) sẽ được mở thông qua một tệp nhờ công cụ chỉnh sửa văn bản như là `vim`. Vì mục đích học tập, tôi đã xây dựng một cửa sổ hội thoại nhỏ mà nó hành xử cũng tương tự như vậy."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Khi hội thoại tương tác rebase bật lên, bạn có thể làm được 3 điều:",
"",
"* Bạn có thể sắp xếp lại commit một cách đơn giản thông qua UI (bạn có thể làm điều này bằng cách kéo thả trên công cụ của chúng tôi).",
"* Bạn có thẻ bỏ qua một vài commit. Điều này được thể hiện qua nút `pick` -- tắt nút `pick` nghĩa là bạn bỏ qua commit đó.",
"* Cuối cùng, bạn có thể nén các commit. Đáng tiếc là trình độ của chúng tôi chưa hỗ trợ được chức năng này do vài vấn đề logic, cho nên tôi sẽ bỏ qua phần này. Nói dơn giản thì -- nó cho phép bạn kết hợp các commit.",
"",
"Tuyệt! Cùng xem qua một ví dụ nào."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Khi bạn bấm nút, một cửa sổ tương tác rebase sẽ xuất hiện. Sắp xếp lại một vài commit (hoặc thậm chí bỏ qua một vài cái) và xem thử kết quả!"
],
"afterMarkdowns": [
"BÙÙM! Git sao chép chính xác các commit mà bạn chọn thông qua UI."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Để hoàn thành cấp độ này, do an interactive rebase and achieve the order shown in the goal visualization. Remember you can always `undo` or `reset` to fix mistakes :D"
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Git Interaktivni Rebase",
"",
"Git cherry-pick je odličen način, ko veš katere commite bi rad (in poznaš njihove hashe) -- težko je premagati njegovo enostavnost.",
"",
"Ampak kaj pa situacija, ko ne veš katere commite želiš? K sreči ima git pokrito tudi to! Uporabimo lahko interaktivni rebase -- gre za najboljši način za pregled commitov, ki jih želiš rebaseati.",
"",
"Spustimo se v podrobnosti ..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Vse kar interaktvini rebase pomeni je, da uporabimo `rebase` ukaz z opcijo `-i`.",
"",
"Če vključiš to opcijo, bo git odprl okno, da ti pokaže, kateri commiti bodo skopirani pod naš ciljni commit rebaseanja. Prav tako pokaže tudi njihove hashe in sporočila, kar je super za razumevanje kaj je kaj.",
"",
"Za \"pravi\" git, odpiranje okna pomeni odpiranje datoteke v urejevalniku kot je `vim`. Za naš namen sem zgradil majhno okno, ki se obnaša enako."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ko se odpre okno za interaktivno rebaseanje, imaš možnost narediti 3 stvari:",
"",
"* Enostavno lahko preurediš commite v vrstni red, ki ga želiš (v našem oknu to dosežeš kar s klikom in vlečenjem miške).",
"* Odločiš se lahko, da čisto izpustiš nekatere commite. To je omogočeno s `pick` -- izklop `pick` opcije pomeni, da bi rad commit izpustil.",
"* Nenazadnje, commite lahko tudi stisnemo. Nažalost naše stopnje tega ne podpirajo zaradi logističnih razlogov, zato bom preskočil podrobnosti tega. Toda če povzamem -- omogoča združevanje commitov.",
"",
"Super! Poglejmo primer."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Ko pritisneš gumb, se bo pojavilo interaktivno okno. Prerazporedi nekaj commitov okoli (ali pa jih odstrani z omit) in poglej rezultat!"
],
"afterMarkdowns": [
"Boom! Git je na dno skopiral commite v točno takšnem vrstnem redu, kot si ga določil v oknu."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Za dokončanje te stopnje naredi interaktvini rebase in doseži vrstni red, kot je predstavljen v ciljni vizualizaciji. Vedno lahko razveljavjiš z `undo` ali ponastaviš z `reset` ukazom, da popraviš napake :D"
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Interaktywny Rebase w Gitcie",
"",
"Cherry-pick'ing jest świetny, gdy wiesz, które commity (_oraz_ znasz ich hasze) chcesz przenieść - trudno jest dyskutować z prostotą, którą zapewnia.",
"",
"Ale co w sytuacji, gdy nie wiesz, które commity chcesz przenieść? Na szczęście git jest przygotowany również na tą sytuację! Możemy wykorzystać do tego interaktywny rebasing - to najlepszy sposób, aby przejrzeć serię commitów, które zamierzasz rebase'ować.",
"",
"Przejdźmy do szczegółów..."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Wszystkie interaktywne znaczniki rebase używają polecenia `rebase` z opcją `-i`.",
"",
"Jeśli włączysz tę opcję, git otworzy okno, aby pokazać ci, które commity mają być skopiowane poniżej wskazanego celu (np. HEAD'a) do rebase'a. W oknie pokażą się również wiadomości i hasze commitów, co zdecydowanie ułatwia zrozumienie co jest czym.",
"",
"Dla \"prawdziwego\" gita, otwarte okno oznacza otwarcie pliku w edytorze tekstu takim jak np. `vim`. Dla naszych potrzeb, zbudowałem małe okno dialogowe, które zachowuje się tak samo."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Kiedy otworzy się interaktywne okno dialogowe rebase, masz możliwość zrobienia dwóch rzeczy w naszej aplikacji edukacyjnej:",
"",
"* Możesz zmienić kolejność commitów poprzez zmianę ich kolejności w oknie (przeciągając je i upuszczając).",
"* Możesz zdecydować się na całkowite pominięcie niektórych commitów. Jest to oznaczone przez `pick` -- wpisanie `pick` off oznacza, że nie chcesz uwzględnić tego commitu.",
"",
"* Warto wspomnieć, że w prawdziwym interaktywnym rebasie możesz zrobić wiele innych rzeczy, takich jak squash (łączenie) commitów, poprawianie wiadomości commitów, a nawet edycja samych commitów. Dla naszych potrzeb jednak skupimy się na tych dwóch operacjach powyżej. *",
"",
"Świetnie! Spójrz na przykład."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Po naciśnięciu przycisku, pojawi się interaktywne okno rebase'owania. Zmień kolejność niektórych commitów (lub usuń niektóre z nich, a co!) i zobacz wynik!"
],
"afterMarkdowns": [
"Boom! Git skopiował commity w ten sam sposób w jaki podałeś to w oknie."
],
"command": "git rebase -i HEAD~4 --aboveAll",
"beforeCommand": "git commit; git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Aby ukończyć ten poziom, zrób interaktywny rebase i osiągnij kolejność pokazaną w wizualizacji celu. Pamiętaj, że zawsze możesz użyć komend `undo` lub `reset` aby naprawić błędy :D"
]
}
}
]
},
}
};

View file

@ -9,11 +9,16 @@ exports.level = {
"zh_CN": "相对引用(^",
"zh_TW": "相對引用(^",
"es_AR": "Referencias relativas (^)",
"es_ES": "Referencias relativas (^)",
"pt_BR": "Referências relativas (^)",
"gl" : "Referencias relativas (^)",
"de_DE": "Relative Referenzen (^)",
"ru_RU": "Относительные ссылки (^)",
"ko" : "상대 참조 (^) (Relative Refs)",
"uk": "Відносні посилання"
"uk": "Відносні посилання",
"vi": "Tham chiếu tương đối (^)",
"sl_SI": "Relativne Reference (^)",
"pl": "Referencje względne (^)",
},
"hint": {
"en_US": "Remember the Caret (^) operator!",
@ -21,12 +26,17 @@ exports.level = {
"ja" : "相対リファレンス(^)を思い出して!",
"de_DE": "Denk an den Dach-Operator (^)!",
"es_AR": "¡No te olvides del operador ^!",
"es_ES": "¡No te olvides del operador ^!",
"pt_BR": "Não se esqueça do operador circunflexo (^)",
"gl" : "Non se esqueza do operador circunflexo (^)",
"zh_CN": "记住操作符(^",
"zh_TW": "不要忘記插入(^)符號!",
"ru_RU": "Не забудь оператор `^`",
"ko" : "(^)연산자를 기억하세요!",
"uk": "Не забудь оператор `^`"
"uk": "Не забудь оператор `^`",
"vi": "Đừng quên dấu mũ (^)!",
"sl_SI": "Spomni se na (^) operator!",
"pl": "Pamiętaj o operatorze karetu (^)!",
},
"startDialog": {
"en_US": {
@ -66,16 +76,16 @@ exports.level = {
"beforeMarkdowns": [
"Let's look at the Caret (^) operator first. Each time you append that to a ref name, you are telling Git to find the parent of the specified commit.",
"",
"So saying `master^` is equivalent to \"the first parent of `master`\".",
"So saying `main^` is equivalent to \"the first parent of `main`\".",
"",
"`master^^` is the grandparent (second-generation ancestor) of `master`",
"`main^^` is the grandparent (second-generation ancestor) of `main`",
"",
"Let's check out the commit above master here"
"Let's check out the commit above main here."
],
"afterMarkdowns": [
"Boom! Done. Way easier than typing the commit hash"
"Boom! Done. Way easier than typing the commit hash."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -83,7 +93,7 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"You can also reference `HEAD` as a relative ref. Let's use that a couple of times to move upwards in the commit tree"
"You can also reference `HEAD` as a relative ref. Let's use that a couple of times to move upwards in the commit tree."
],
"afterMarkdowns": [
"Easy! We can travel backwards in time with `HEAD^`"
@ -141,16 +151,16 @@ exports.level = {
"beforeMarkdowns": [
"Regardons l'opérateur circonflexe (^) d'abord. Chaque fois que vous le faites suivre un nom de référence, vous êtes en train de demander à Git de trouver le parent du commit spécifié.",
"",
"Ainsi, `master^` est équivalent à \"le premier parent de `master`\".",
"Ainsi, `main^` est équivalent à \"le premier parent de `main`\".",
"",
"`master^^` est le grand-parent (ancêtre de seconde génération) de `master`",
"`main^^` est le grand-parent (ancêtre de seconde génération) de `main`",
"",
"Faisons un checkout du commit avant master."
"Faisons un checkout du commit avant main."
],
"afterMarkdowns": [
"Boum ! Fini. Bien plus facile qu'écrire l'identifiant du commit."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -216,16 +226,16 @@ exports.level = {
"beforeMarkdowns": [
"Schauen wir uns zuerst den Dach-Operator (`^`) an. Jedes mal wenn du ihn hinter einen Referenz-Namen setzt, sagst du Git damit, dass es zum Vorgänger des angegebenen Commits gehen soll.",
"",
"Das heißt `master^` ist gleichbedeutend mit \"direkter Vorgänger des Commits, auf den `master` zeigt\".",
"Das heißt `main^` ist gleichbedeutend mit \"direkter Vorgänger des Commits, auf den `main` zeigt\".",
"",
"`master^^` ist also der Vorgänger des Vorgängers von `master`.",
"`main^^` ist also der Vorgänger des Vorgängers von `main`.",
"",
"Wir checken jetzt mal den Commit vor `master` aus:"
"Wir checken jetzt mal den Commit vor `main` aus:"
],
"afterMarkdowns": [
"Bämm! Fertig. Einfacher, als den Commit-Hash zu tippen (oder zu kopieren)."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -291,16 +301,16 @@ exports.level = {
"beforeMarkdowns": [
"Veamos el operador ^ primero. Cada vez que le agregás eso al nombre de una referencia, le estás diciendo a git que use el padre del commit especificado.",
"",
"Entonces, decir `master^` es equivalente a \"el primer padre de `master`\".",
"Entonces, decir `main^` es equivalente a \"el primer padre de `main`\".",
"",
"`master^^` es el _abuelo_ (segunda generación de ancestros) de `master`",
"`main^^` es el _abuelo_ (segunda generación de ancestros) de `main`",
"",
"Veamos el commit que está antes de master acá"
"Veamos el commit que está antes de main acá."
],
"afterMarkdowns": [
"¡Boom! Ahí está. Mucho más simple que tipear el hash de ese commit"
"¡Boom! Ahí está. Mucho más simple que tipear el hash de ese commit."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -308,7 +318,7 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"También podés referenciar a `HEAD` como una referencia relativa. Usémoslo un par de veces para movernos hacia atrás en nuestro árbol"
"También podés referenciar a `HEAD` como una referencia relativa. Usémoslo un par de veces para movernos hacia atrás en nuestro árbol."
],
"afterMarkdowns": [
"¡Fácil! Podemos volver en el tiempo con `HEAD^`"
@ -329,6 +339,81 @@ exports.level = {
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Referencias relativas",
"",
"Moverse por git usando los hashes de los commits puede volverse un tanto tedioso. En el mundo real no vas a tener una visualización de commits tan linda en la terminal, así que vas a tener que usar `git log` para ver los hashes.",
"",
"Peor aún, los hashes en general son mucho más largos en el git real, también. Por ejemplo, el hash del commit que introduje en el nivel anterior es `fed2da64c0efc5293610bdd892f82a58e8cbc5d8`. No es algo particularmente fácil de nombrar...",
"",
"Lo interesante es que git es bastante astuto con los hashes. Sólo requiere que especifiques una cantidad de caracteres suficientes para identificar unívocamente al commit. Entonces, yo podría simplemente tipear `fed2` en lugar de esa cadena larga de arriba."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Como ya dije, especificar los commits por su hash no es la manera más conveniente, y por eso git tiene referencias relativas. ¡Son geniales!",
"",
"Con las referencias relativas puedes arrancar de algún lugar recordable (como la rama `bugFix`, o `HEAD`) y trabajar desde ahí.",
"",
"Los commits relativos son poderosos, pero ahora vamos a presentar sólo dos formas simples:",
"",
"* Moverse un commit hacia atrás con `^`",
"* Moverse una cantidad de commits hacia atrás con `~<num>`"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos el operador ^ primero. Cada vez que le agregas eso al nombre de una referencia, le estás diciendo a git que use el padre del commit especificado.",
"",
"Entonces, decir `main^` es equivalente a \"el primer padre de `main`\".",
"",
"`main^^` es el _abuelo_ (segunda generación de ancestros) de `main`",
"",
"Veamos el commit que está antes de main aquí."
],
"afterMarkdowns": [
"¡Zas! Ahí está. Mucho más simple que escribir el hash de ese commit."
],
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"También puedes referenciar a `HEAD` como una referencia relativa. Usémoslo un par de veces para movernos hacia atrás en nuestro árbol."
],
"afterMarkdowns": [
"¡Fácil! Podemos volver en el tiempo con `HEAD^`"
],
"command": "git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^",
"beforeCommand": "git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, haz checkout sobre el padre del commit de `bugFix`. Esto va a detachear a `HEAD`.",
"",
"Puedes especificar el hash si quieres, pero mejor ¡trata de usar la referencia relativa!"
]
}
}
]
},
"pt_BR": {
"childViews": [
{
@ -366,16 +451,16 @@ exports.level = {
"beforeMarkdowns": [
"Vamos dar uma olhada no operador circunflexo (^) primeiro. Cada vez que você adicioná-lo a um nome de referência, você está dizendo ao Git para encontrar o pai do commit especificado.",
"",
"Então, dizer `master^` é equivalente a \"o primeiro pai do `master`\".",
"Então, dizer `main^` é equivalente a \"o primeiro pai do `main`\".",
"",
"`master^^` é o avô (ancestral de segunda geração) do `master`",
"`main^^` é o avô (ancestral de segunda geração) do `main`",
"",
"Vamos fazer checkout do commit logo acima do master"
"Vamos fazer checkout do commit logo acima do main."
],
"afterMarkdowns": [
"Boom! Pronto. Muito mais fácil que digitar o hash do commit"
"Boom! Pronto. Muito mais fácil que digitar o hash do commit."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -383,7 +468,7 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Você também pode usar o `HEAD` como parte de uma referência relativa. Vamos usar isso para nos mover para cima algumas vezes na árvore de commits"
"Você também pode usar o `HEAD` como parte de uma referência relativa. Vamos usar isso para nos mover para cima algumas vezes na árvore de commits."
],
"afterMarkdowns": [
"Fácil! Podemos viajar para trás no tempo com `HEAD^`"
@ -404,6 +489,81 @@ exports.level = {
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Referencias relativas",
"",
"Moverse por a árbore de git usando os códigos hash dos commits pode volverse un pouco tedioso. Neste mundo real non vas ter unha visualización dos commits tan bonita no terminal, así que vas ter que usar `git log` para ver cada código hash.",
"",
"Inda peor, os códigos hash són xeralmente moito máis grandes no mundo real. Por exemplo, o hash do commit que introduxemos no nivel anterior é `fed2da64c0efc5293610bdd892f82a58e8cbc5d8`. Non é algo sinxelo de lembrar.",
"",
"O bo é que git aínda afina cos hashes. El só precisa que expecifiques a cantidade mínima de caracteres suficientes para identificar unívocamente ó commit. Entón eu podo escribir `fed2` e non o hash completo."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Como xa dixemos, indicar os commits polo seu código hash non é a forma máis convinte, e é por eso que git ten referencias relativas. ¡Son a caña!",
"",
"Cas referencias relativas, podes comezar por un punto sinxelo de lembrar (como a rama `bugFix` ou o `HEAD`) e referenciar a partir de ahí.",
"",
"Os commits relativos son poderosos, pero agora imos presentar só dous formas sinxelas:",
"",
"* Moverse un commit por riba con `^`",
"* Mover unha cantidade de commits atrás con `~<num>`"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Votémoslle unha ollada o operador (^) primeiro. Cada vez que o engadimos a unha referencia, estaslle dicindo a commit que queres o pai de esa referencia.",
"",
"Entón, dicir `main^` é equivalente a \"o primeiro pai do `main`\".",
"",
"`main^^` é o avó (ancestral de segunda xeración) do `main`",
"",
"Imos facer checkout do commit que está enriba de main."
],
"afterMarkdowns": [
"Boom! Ahí o tes. Moito máis rápido que por o hash do commit."
],
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Tamén podes usar o `HEAD` como parte dunha referencia relativa. Ímolo utilizar para nos mover uns commits cara arriba na árbore."
],
"afterMarkdowns": [
"¡Chupado! Podemos viaxar cara atrás no tempo con `HEAD^`"
],
"command": "git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^",
"beforeCommand": "git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Para completar este nivel, fai checkout do commit pai de `bugFix`. Iso soltará o `HEAD`.",
"",
"¡Podes indicar o hash que queiras, pero intenta empregar as referencias relativas, é moito mellor!"
]
}
}
]
},
"zh_CN": {
"childViews": [
{
@ -441,16 +601,16 @@ exports.level = {
"beforeMarkdowns": [
"首先看看操作符 (^)。把这个符号加在引用名称的后面,表示让 Git 寻找指定提交记录的父提交。",
"",
"所以 `master^` 相当于“`master` 的父节点”。",
"所以 `main^` 相当于“`main` 的父节点”。",
"",
"`master^^` 是 `master` 的第二个父节点",
"`main^^` 是 `main` 的第二个父节点",
"",
"现在咱们切换到 master 的父节点"
"现在咱们切换到 main 的父节点"
],
"afterMarkdowns": [
"搞定。这种方式是不是比输入哈希值方便多了?!"
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -516,16 +676,16 @@ exports.level = {
"beforeMarkdowns": [
"首先看看插入(^)這一個符號。把這個符號接在某一個 reference 後面,就表示你告訴 git 去找到該 reference 所指向的 commit 的 parent commit。",
"",
"所以 `master^` 相當於 \"`master` 的 parent commit\"。",
"所以 `main^` 相當於 \"`main` 的 parent commit\"。",
"",
" `master^^` 是 `master` 的 grandparent commit往前推兩代",
" `main^^` 是 `main` 的 grandparent commit往前推兩代",
"",
"切換到 master的 parent commit"
],
"afterMarkdowns": [
"看吧!完成了。這種方式比輸入代表 commit 的 hash 值簡單多了!"
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -591,16 +751,16 @@ exports.level = {
"beforeMarkdowns": [
"まずはカレット(^)から始めましょう。リファレンス名にカレットを追加すると、指定コミットの親コミットを見つけるようにとgitに命令を出しています。",
"",
"なので `master^`と記述すれば、\"`master`の一個上の親\"、という意味になります。",
"なので `main^`と記述すれば、\"`main`の一個上の親\"、という意味になります。",
"",
"そして`master^^`とはその親の一つの上のコミット(2代前の親)を指します。",
"そして`main^^`とはその親の一つの上のコミット(2代前の親)を指します。",
"",
"masterの上のコミットをここで見てみましょう"
],
"afterMarkdowns": [
"やりました!コミットハッシュを書くよりずっと簡単ですね。"
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -666,16 +826,16 @@ exports.level = {
"beforeMarkdowns": [
"Для начала рассмотрим оператор каретки (^). Когда мы добавляем его к имени ссылки, Git воспринимает это как указание найти родителя указанного коммита.",
"",
"Так что `master^` означает \"первый предок ветки `master`\".",
"Так что `main^` означает \"первый родитель ветки `main`\".",
"",
"`master^^` означает предок предка ветки `master`",
"`main^^` означает прародитель (родитель родителя) `main`",
"",
"Получим предка ветки `master` на практике"
"Давайте переключимся на коммит Выше `main`"
],
"afterMarkdowns": [
"Опачки! Готово. Сильно проще, чем поиск и указание хеша."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -741,16 +901,16 @@ exports.level = {
"beforeMarkdowns": [
"먼저 캐럿 (^) 연산자 부터 알아보겠습니다. 참조 이름에 하나씩 추가할 때마다, 명시한 커밋의 부모를 찾게 됩니다.",
"",
"`master^`는 \"`master`의 부모\"와 같은 의미 입니다.",
"`main^`는 \"`main`의 부모\"와 같은 의미 입니다.",
"",
"`master^^` 는 \"`master`의 조부모(부모의 부모)\"를 의미합니다",
"`main^^` 는 \"`main`의 조부모(부모의 부모)\"를 의미합니다",
"",
"master 위에 있는 부모를 체크아웃 해 봅시다."
"main 위에 있는 부모를 체크아웃 해 봅시다."
],
"afterMarkdowns": [
"Boom! 됬습니다. 커밋의 해시를 입력하는 것보다 훨씬 쉬운 방법입니다."
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -816,16 +976,16 @@ exports.level = {
"beforeMarkdowns": [
"Розберемось спочатку з оператором каретки (^). Кожна каретка додана до посилання (напр. до імені коміту) вказує git що потрібно знайти батька посилання до якого застосована каретка.",
"",
"Тож `master^` тотожнє до \"перший предок посилання `master`\".",
"Тож `main^` тотожнє до \"перший предок посилання `main`\".",
"",
"`master^^` це дідусь (предок другого покоління) посилання `master`",
"`main^^` це дідусь (предок другого покоління) посилання `main`",
"",
"Давайте перейдемо на коміт трохи вище від master:"
"Давайте перейдемо на коміт трохи вище від main:"
],
"afterMarkdowns": [
"Бум! Готово. Трохи простіше ніж набирати хеш коміту"
],
"command": "git checkout master^",
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
@ -853,6 +1013,231 @@ exports.level = {
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Tham chiếu tương đối",
"",
"Dịch chuyển trong Git bằng cách chỉ định mã băm(hash) của commit cỏ vẻ hơi buồn tẻ. Trong đời thực thì sẽ không có mô tả git trực quan ngay bên cạnh terminal của bạn đâu, nên nếu bạn muốn nhìn mã băm của commit thì phải dùng `git log` thôi.",
"",
"Hơn nữa, mã băm thực tế thường dài hơn rất nhiều. Ví dụ, mã băm của commit được giới thiệu trong phần trước là `fed2da64c0efc5293610bdd892f82a58e8cbc5d8`. Đọc mà xoắn hết cả lưỡi...",
"",
"Được cái là Git cũng khá thông minh về mã băm. Nó chỉ yêu cầu bạn chỉ định mã băm đủ để xác định commit. Cho nên tôi có thể đơn giản chỉ cần gõ `fed2` thay vì cái chuỗi dài ngoằng phía trên."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Như tôi đã nói, xác định commit bằng mã băm của nó chẳng hề thuận tiện tẹo nào, đó là tại sao Git có những `tham chiếu tương đối`. Chúng rất tuyệt vời!",
"",
"Với tham chiếu tương đối, bạn có thể bắt đầu từ những nơi có thể ghi nhớ được (như là nhánh `bugFix` hoặc `HEAD`) và làm việc trên đó.",
"",
"Những commits tương đối rất mạnh mẽ, nhưng chúng tôi sẽ chỉ giới thiệu 2 loại đơn giản sau:",
"",
"* Dịch chuyển 1 commit lên trên trong 1 lần với `^`",
"* Dịch chuyển nhiều commit lên trên trong 1 lần với `~<số>`"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Xem thử cái dấu mũ (^) trước nào. Mỗi lần bạn nối nó với một cái tên tham chiếu, bạn đang ra lệnh cho Git tìm kiếm cha của một commit cụ thể.",
"",
"Cho nên `main^` nghĩa là \"cha đầu tiên của `main`\".",
"",
"`main^^` là ông nội (tổ tiên thế hệ 2) của `main`",
"",
"Thử nhảy sang commit trước main nào"
],
"afterMarkdowns": [
"BÙUM! Đã xong. Đơn giản hơn gõ mã băm nhiều"
],
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Bạn cũng có thể dùng `HEAD` như là tham chiếu tương đối. Thử dùng nó để leo commit vài lần nào"
],
"afterMarkdowns": [
"Game là dễ! Du hành ngược thời gian với `HEAD^`"
],
"command": "git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^",
"beforeCommand": "git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Để hoàn thành cấp độ này, nhảy sang cha của `bugFix`. Tức là tháo `HEAD`.",
"",
"Nếu muốn thì bạn có thể dùng mã băm, nhưng thế thì còn gì vui nữa dùng tham chiếu tương đối đi!"
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Relativne Reference",
"",
"Premikanje po Gitu z določanjem hashev commitov je lahko včasih nerodno. V praksi ne boš imel na voljo lepe vizualizacije drevesa zraven ukaznega terminala, zato boš moral uporabljati `git log`, da boš videl hashe.",
"",
"Hashi so ponavadi v praksi tudi veliko daljši. Naprimer, hash commita, predstavljenega v prejšnji stopnji, je `fed2da64c0efc5293610bdd892f82a58e8cbc5d8`. Ni ravno preprosto za izgovoriti ...",
"",
"Pozitivna stran je, da je Git pameten glede hashev. Zahteva, da napišeš le toliko znakov hasha, da lahko prepozna unikaten commit. Tako lahko napišem `fed2`, namesto dolge verzije zgoraj."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Kot sem rekel, izbiranje commitov po njihovih hashih ni ravno najpriročnejša stvar na svetu, zato ima Git relativne reference. In te so super!",
"",
"Z relativni referencami lahko izhajaš iz nekje (npr. branch `bugFix` ali `HEAD`) in delaš od tam.",
"",
"Relativni commiti so močni in obsegajoči, ampak tu bomo predstavili dva preprosta:",
"",
"* Premikanje navzgor en commit naenkrat z `^`",
"* Premikanje navzgor n-krat z `~<n>`"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poglejmo najprej operator `^`. Vsakič, ko pripneš to imenu reference, poveš Gitu, naj najde starša tega commita.",
"",
"Torej `main^` je isto kot \"prvi starš brancha `main`\".",
"",
"`main^^` je stari starš (prednik druge generacije) `main`.",
"",
"Checkoutajmo sedaj commit nad masterjem."
],
"afterMarkdowns": [
"Boom! Narejeno. Veliko enostavneje kot tipkanje hasha commita."
],
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Prav tako se lahko sklicuješ na `HEAD` kot relativno referenco. Uporabimo to nekajkrat, da se pomakenmo višje po drevesu commitov."
],
"afterMarkdowns": [
"Enostavno! Lahko potujemo nazaj v čas z `HEAD^`."
],
"command": "git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^",
"beforeCommand": "git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Za dokončanje te stopnje, checkoutaj starša commita `bugFix`. To bo ločilo `HEAD`.",
"",
"Hash lahko določiš, če želiš, ampak probaj raje z relativnimi referencami!"
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"## Relatywne referencje",
"",
"Poruszanie się w Gitcie poprzez określanie haszy commitów może być trochę nudne. W prawdziwym świecie nie będziesz miał ładnej wizualizacji drzewa commitów obok swojego terminalu (chyba, że będziesz używać Fork'a lub TortoiseGit'a). Będziesz musiał użyć `git log` aby zobaczyć hasz.",
"",
"Co więcej, hasz jest zazwyczaj o wiele dłuższy w prawdziwym Gitcie. Na przykład, hash commitu, które był na początku poprzedniego poziomu to `fed2da64c0efc5293610bdd892f82a58e8cbc5d8`. Spróbuj to przeczytać!",
"",
"Plusem jest to, że Git jest sprytny jeżeli chodzi o hasze. Wymaga jedynie podania tylu znaków haszu, aż do momentu, gdy jednoznacznie zidentyfikuje konkretny commit. Dlatego mogę wpisać jedynie `fed2` zamiast długiego łańcucha powyżej."
]
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Jak już powiedzieliśmy, wybieranie commitów używając ich hasza nie jest najprzyjemniejszą rzeczą w życiu, dlatego Git ma referencje względne. Są niesamowite!",
"",
"Korzystając z referencji względnych, możesz zacząć od miejsca, które zapamiętasz (jak np. gałąź `bugFix` lub `HEAD`) i pracować stamtąd.",
"",
"Relatywne commity są potężne, ale pokażemy tu tylko dwie proste sytuacje:",
"",
"* Poruszanie się wstecz o jeden commit `^`",
"* Poruszanie się wstecz o ileś commitów `~<num>`"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Spójrzmy najpierw na operator Karety / daszek (^). Za każdym razem, gdy dodajesz go do referencji względnej, mówisz Gitowi, aby znalazł rodzica określonego commita.",
"",
"Więc wpisując `main^` mamy na myśli \"pierwszego rodzica z gałęzi `main`\".",
"",
"`main^^` to dziadek (przodek drugiego stopnia) gałęzi `main`",
"",
"Zcheckoutujmy commit powyżej `main`."
],
"afterMarkdowns": [
"Boom! Zrobione. O wiele łatwiej niż wpisując hasz commitu."
],
"command": "git checkout main^",
"beforeCommand": "git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Możesz również odwołać się do `HEAD` jako referencji względnej. Użyjmy tego kilka razy, aby przesunąć się w górę drzewa commitów."
],
"afterMarkdowns": [
"Łatwizna! Możemy podróżować do tyłu w czasie używając `HEAD^`"
],
"command": "git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^",
"beforeCommand": "git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Aby ukończyć ten poziom, zcheckoutuj commit'a-rodzica z gałęzi `bugFix`. To spowoduje odczepienie `HEAD`a.",
"",
"Możesz wybrać commit'a po haszu jeżeli chcesz, ale spróbuj wykorzystać to czego się nauczyłeś i użyć referencji względnej!"
]
}
}
]
},
}
};

View file

@ -1,6 +1,6 @@
exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C6\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C0\",\"id\":\"bugFix\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C2\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C3\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C5\"],\"id\":\"C6\"}},\"HEAD\":{\"target\":\"C1\",\"id\":\"HEAD\"}}",
"solutionCommand": "git branch -f master C6;git checkout HEAD~1;git branch -f bugFix HEAD~1",
"solutionCommand": "git branch -f main C6;git checkout HEAD~1;git branch -f bugFix HEAD~1",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C4\",\"id\":\"master\"},\"bugFix\":{\"target\":\"C5\",\"id\":\"bugFix\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C2\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C3\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C5\"],\"id\":\"C6\"}},\"HEAD\":{\"target\":\"C2\",\"id\":\"HEAD\"}}",
"hint": {
"en_US": "You'll need to use at least one direct reference (hash) to complete this level",
@ -8,25 +8,35 @@ exports.level = {
"zh_CN": "这一关至少要用到一次直接引用 (即哈希值)",
"zh_TW": "這一關至少要用到一次直接參考hash",
"es_AR": "Vas a necesitar usar al menos una referencia directa (hash) para completar este nivel",
"es_ES": "Vas a necesitar usar al menos una referencia directa (hash) para completar este nivel",
"pt_BR": "Você precisará usar pelo menos uma referência direta (hash) para completar este nível",
"gl" : "Precisarás usar polo menos unha referencia directa (hash) para completar este nivel",
"de_DE": "Du musst mindestens einen Hash benutzen, um dieses Level zu schaffen",
"ja" : "このレベルをクリアするには少なくとも一つの直接リファレンスhashを使用する必要があります",
"ru_RU": "Понадобится использовать как минимум одну прямую ссылку (хеш), чтобы пройти этот уровень",
"ko" : "이번 레벨을 완료하려면 최소 한번은 직접 참조(해시)를 사용해야 합니다.",
"uk": "Тобі потрібно використати як мінімум одне пряме посилання (хеш) щоб пройти цей рівень"
"uk": "Тобі потрібно використати як мінімум одне пряме посилання (хеш) щоб пройти цей рівень",
"vi": "Bạn sẽ cần dùng ít nhất một tham chiếu trực tiếp (mã băm) để hoàn thành cấp độ này",
"sl_SI": "Moral boš uporabiti vsaj eno direktno referenco (hash) za dokončanje te stopnje.",
"pl": "Aby ukończyć ten poziom, musisz użyć co najmniej jednego bezpośredniej referencji (hasza).",
},
"name": {
"en_US": "Relative Refs #2 (~)",
"de_DE": "Relative Referenzen #2 (~)",
"ja" : "相対リファレンス その2 (~)",
"es_AR": "Referencias relativas #2 (~)",
"es_ES": "Referencias relativas #2 (~)",
"pt_BR": "Referências relativas #2 (~)",
"gl" : "Referencias relativas #2 (~)",
"fr_FR": "Références relatives #2 (~)",
"zh_CN": "相对引用2~",
"zh_TW": "相對引用二(~",
"ru_RU": 'Относительные ссылки №2',
"ko" : "상대 참조 #2 (~)",
"uk": "Відносні посилання №2"
"uk": "Відносні посилання №2",
"vi": "Tham chiếu tương đối #2 (~)",
"sl_SI": "Relativne Reference #2 (~)",
"pl": "Referencje względne #2 (~)"
},
"startDialog": {
"en_US": {
@ -40,7 +50,7 @@ exports.level = {
"Say you want to move a lot of levels up in the commit tree. It might be tedious to type `^` several times, so Git also has the tilde (~) operator.",
"",
"",
"The tilde operator (optionally) takes in a trailing number that specifies the number of parents you would like to ascend. Let's see it in action"
"The tilde operator (optionally) takes in a trailing number that specifies the number of parents you would like to ascend. Let's see it in action."
]
}
},
@ -67,9 +77,9 @@ exports.level = {
"",
"One of the most common ways I use relative refs is to move branches around. You can directly reassign a branch to a commit with the `-f` option. So something like:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"moves (by force) the master branch to three parents behind HEAD."
"moves (by force) the main branch to three parents behind HEAD."
]
}
},
@ -82,7 +92,7 @@ exports.level = {
"afterMarkdowns": [
"There we go! Relative refs gave us a concise way to refer to `C1` and branch forcing (`-f`) gave us a way to quickly move a branch to that location."
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -92,7 +102,7 @@ exports.level = {
"markdowns": [
"Now that you have seen relative refs and branch forcing in combination, let's use them to solve the next level.",
"",
"To complete this level, move `HEAD`, `master`, and `bugFix` to their goal destinations shown."
"To complete this level, move `HEAD`, `main`, and `bugFix` to their goal destinations shown."
]
}
}
@ -136,9 +146,9 @@ exports.level = {
"",
"Una de las formas más comunes en que uso las referencias relativas es para mover las ramas. Podés reasignar directamente una rama a un commit usando la opción `-f`. Así que algo como:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"Mueve (forzadamente) la rama master tres padres atrás de HEAD."
"Mueve (forzadamente) la rama main tres padres atrás de HEAD."
]
}
},
@ -151,7 +161,7 @@ exports.level = {
"afterMarkdowns": [
"¡Ahí vamos! Las referencias relativas nos dieron una manera concisa de referenciar a `C1`, y forzar la rama (`-f`) nos dio una manera rápida de mover la rama a esa ubicación"
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -161,7 +171,76 @@ exports.level = {
"markdowns": [
"Ahora que viste las referencias relativas y el forzar ramas combinados, usémoslos para resolver el siguiente nivel.",
"",
"Para completar este nivel, mové `HEAD`, `master` y `bugFix` a sus destinos finales."
"Para completar este nivel, mové `HEAD`, `main` y `bugFix` a sus destinos finales."
]
}
}
]
},
"es_ES": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### El operador \"~\"",
"",
"Digamos que quieres moverte un montón de niveles atrás en tu árbol de commits. Podría ser tedioso escribir `^` muchas veces, por lo que git tiene el operador ~.",
"",
"",
"El operador ~ (opcionalmente) toma una cantidad que especifica la cantidad de padres que quieres volver hacia atrás. Veámoslo en acción"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Especifiquemos una cantidad de commits hacia atrás con `~`."
],
"afterMarkdowns": [
"¡Zas! Bien conciso -- las referencias relativas la rompen."
],
"command": "git checkout HEAD~4",
"beforeCommand": "git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Forzando las ramas",
"",
"Ahora que eres un experto en las referencias relativas, *usémoslas* para algo.",
"",
"Una de las formas más comunes en que uso las referencias relativas es para mover las ramas. Puedes reasignar directamente una rama a un commit usando la opción `-f`. Algo así como:",
"",
"`git branch -f main HEAD~3`",
"",
"Mueve (forzadamente) la rama main tres padres por detrás de HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Veamos ese comando previo en acción"
],
"afterMarkdowns": [
"¡Allá vamos! Las referencias relativas nos proporcionaron una manera concisa de referenciar a `C1`, y forzar la rama (`-f`) nos dio una manera rápida de mover la rama a esa ubicación"
],
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Ahora que viste las referencias relativas y el forzar ramas combinados, usémoslos para resolver el siguiente nivel.",
"",
"Para completar este nivel, mueve `HEAD`, `main` y `bugFix` a sus destinos finales."
]
}
}
@ -205,9 +284,9 @@ exports.level = {
"",
"Uma das situações mais comuns na qual eu uso referências relativas é quando quero trocar ramos de lugar. Você pode redefinir diretamente o commit para o qual um ramo aponta com a opção `-f`. Desta forma, o seguinte comando:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"Move (à força) o ramo master 3 ancestrais acima do HEAD."
"Move (à força) o ramo main 3 ancestrais acima do HEAD."
]
}
},
@ -218,9 +297,9 @@ exports.level = {
"Vejamos o comando anterior em ação"
],
"afterMarkdowns": [
"Aqui vamos nós! As referências relativas nos deram uma forma concisa de nos referirmos ao `C1`, e a movimentação de ramos (com `-f`) nos deu uma forma de apontar rapidamente um ramo para esse local"
"Aqui vamos nós! As referências relativas nos deram uma forma concisa de nos referirmos ao `C1`, e a movimentação de ramos (com `-f`) nos deu uma forma de apontar rapidamente um ramo para esse local."
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -230,7 +309,76 @@ exports.level = {
"markdowns": [
"Agora que você viu referências relativas e movimentação de ramos combinadas, vamos usá-las para resolver o próximo nível.",
"",
"Para completar este nível, mova o `HEAD` e os ramos `master` e `bugFix` para os destinos mostrados no objetivo."
"Para completar este nível, mova o `HEAD` e os ramos `main` e `bugFix` para os destinos mostrados no objetivo."
]
}
}
]
},
"gl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### O operador \"~\"",
"",
"Digamos que queres moverte un montón de commits cara atrás nunha árbore de git. Sería moi tedioso escribir `^` moitas veces, e por iso que git tamén ten o operador (`~`).",
"",
"",
"Pódeselle pasar un número (opcionalmente) despois da tilde, especificando o número de commits que se quere mover cara atrás. Mira como é en acción."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Imos especificar un número de commits cara atrás con `~`."
],
"afterMarkdowns": [
"¡Veeeña! Ben apuntado -- as referencias relativas son a leche."
],
"command": "git checkout HEAD~4",
"beforeCommand": "git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Forzando as ramas",
"",
"Agora que eres un especialista en referencias relativas, imos *usalas* para algunha cousiña.",
"",
"Un dos usos máis comúns para o uso das referencias relativas é para movelas ramas de lugar. Ti podes reasignar directamente unha rama a un commit usando a opción `-f`. Así que con algo coma:",
"",
"`git branch -f main HEAD~3`",
"",
"Move (de forma forzosa) a rama main 3 commits enriba do HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Vexamos o comando anterior en acción"
],
"afterMarkdowns": [
"¡Agora é o a nosa quenda! As referencias relativas nos darán unha forma concisa de nos referír a `C1`, e forzar a rama (con `-f`) deunos unha forma rápida de movela rama `main` a esa posición."
],
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Xa viches as referencias relativas e o movemento de ramas combinadas, ímolas usar para resolver o próximo exercicio.",
"",
"Para completar este nivel, mova o `HEAD` e as ramas `main` e `bugFix` para os destinos mostrados no obxectivo."
]
}
}
@ -247,7 +395,7 @@ exports.level = {
"Disons que vous souhaitez remonter beaucoup de niveaux dans l'arbre des commits. Cela peut être ennuyeux d'utiliser `^` plusieurs fois, ainsi Git a aussi l'opérateur tilde (~).",
"",
"",
"L'opérateur tilde prend optionnellement à sa suite un nombre qui spécifie le nombre de parents que vous souhaitez remonter. Voyons cela en action"
"L'opérateur tilde prend optionnellement à sa suite un nombre qui spécifie le nombre de parents que vous souhaitez remonter. Voyons cela en action."
]
}
},
@ -274,9 +422,9 @@ exports.level = {
"",
"L'une des principales façons dont j'utilise les références relatives est pour réorganiser les branches. Vous pouvez directement réassigner les branches à un commit avec l'option `-f`. Ainsi quelque chose comme :",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"bouge (de force) la branche master à trois parents derrière HEAD."
"bouge (de force) la branche main à trois parents derrière HEAD."
]
}
},
@ -284,12 +432,12 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Voyons l'effet de la précédente commande"
"Voyons l'effet de la précédente commande."
],
"afterMarkdowns": [
"On y est ! Les références relatives nous donne une méthode concise pour référencer `C1` et le forçage de branche (`-f`) nous donne une méthode rapide pour bouger une branche à cet emplacement."
"On y est ! Les références relatives nous donnent une méthode concise pour référencer `C1` et le forçage de branche (`-f`) nous donne une méthode rapide pour bouger une branche à cet emplacement."
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -299,7 +447,7 @@ exports.level = {
"markdowns": [
"Maintenant que vous avez vu les références relatives et le forçage de branche, utilisons-les pour résoudre le niveau suivant.",
"",
"Pour compléter ce niveau, bouger `HEAD`, `master`, et `bugFix` à leurs destinations désignées."
"Pour compléter ce niveau, bouger `HEAD`, `main`, et `bugFix` à leurs destinations désignées."
]
}
}
@ -313,7 +461,7 @@ exports.level = {
"markdowns": [
"### Der \"~\"-Operator",
"",
"Nehmen wir an du willst viele Schritte im Commit-Baum zurückgehen. Dann wird es schnell mühsam immer wieder `^` einzugeben; deswegen gibt es in Git den Tilde-Operator `~`.",
"Nehmen wir an, du willst viele Schritte im Commit-Baum zurückgehen. Dann wird es schnell mühsam immer wieder `^` einzugeben; deswegen gibt es in Git den Tilde-Operator `~`.",
"",
"Der Tilde-Operator akzeptiert optional eine Zahl, mit der du angeben kannst, wieviele Vorgänger du zurückgehen willst. Keine Anzahl anzugeben, bewirkt dasselbe wie `~1`."
]
@ -323,7 +471,7 @@ exports.level = {
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Geben wir mit `~` an wieviele Commits wir zurückgehen wollen"
"Geben wir mit `~` an, wieviele Commits wir zurückgehen wollen."
],
"afterMarkdowns": [
"Peng! So einfach -- relative Referenzen sind super."
@ -340,11 +488,11 @@ exports.level = {
"",
"Du bist jetzt Experte in Sachen relative Referenzen, also lass sie uns mal richtig einsetzen.",
"",
"Das Verschieben von Branches ist einer der häufigsten Anwendungsfälle dafür. Du kannst einen Branchnamen direkt auf einen bestimmten Commit setzen (_ohne_ ihne vorher ausgecheckt haben zu müssen!) indem du den Parameter `-f` benutzt. So in etwa:",
"Das Verschieben von Branches ist einer der häufigsten Anwendungsfälle dafür. Du kannst einen Branchnamen direkt auf einen bestimmten Commit setzen (_ohne_ ihn vorher ausgecheckt haben zu müssen!), indem du den Parameter `-f` benutzt. So in etwa:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"Das bewegt (erzwungenermaßen) den `master` auf den Commit drei Vorgänger vor `HEAD`."
"Das bewegt (erzwungenermaßen) den `main` auf den Commit drei Vorgänger vor `HEAD`."
]
}
},
@ -357,7 +505,7 @@ exports.level = {
"afterMarkdowns": [
"Das war's schon! Relative Referenzen ermöglichen es uns den Commit `C1` sehr einfach anzugeben und `git branch -f` ermöglicht es uns, den Branch sehr schnell auf diesen Commit zu setzen."
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -367,7 +515,7 @@ exports.level = {
"markdowns": [
"Jetzt wo du relative Referenzen und erzwungenes Branching in Kombination gesehen hast können wir damit den nächsten Level bewältigen.",
"",
"Bewege `HEAD`, `master` und `bugFix` an die jeweils angegebenen Positionen, um diesen Level abzuschließen."
"Bewege `HEAD`, `main` und `bugFix` an die jeweils angegebenen Positionen, um diesen Level abzuschließen."
]
}
}
@ -411,9 +559,9 @@ exports.level = {
"",
"我使用相对引用最多的就是移动分支。可以直接使用 `-f` 选项让分支指向另一个提交。例如:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"上面的命令会将 master 分支强制指向 HEAD 的第 3 级父提交。"
"上面的命令会将 main 分支强制指向 HEAD 的第 3 级父提交。"
]
}
},
@ -426,7 +574,7 @@ exports.level = {
"afterMarkdowns": [
"这就对了! 相对引用为我们提供了一种简洁的引用提交记录 `C1` 的方式, 而 `-f` 则容许我们将分支强制移动到那个位置。"
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -436,7 +584,7 @@ exports.level = {
"markdowns": [
"既然你已经看过相对引用与强制移动分支的演示了,那么赶快使用这些技巧来挑战这一关吧!",
"",
"要完成此关,移动 `HEAD``master` 和 `bugFix` 到目标所示的位置。"
"要完成此关,移动 `HEAD``main` 和 `bugFix` 到目标所示的位置。"
]
}
}
@ -480,9 +628,9 @@ exports.level = {
"",
"我使用相對引用最多的就是移動分支。你可以使用 `-f` 選項直接讓分支指向另一個 commit。舉個例子:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"(強制)移動 master 指向從 HEAD 往上數的第三個 parent commit。"
"(強制)移動 main 指向從 HEAD 往上數的第三個 parent commit。"
]
}
},
@ -490,7 +638,7 @@ exports.level = {
"type": "ModalAlert",
"options": {
"markdowns": [
"要完成這一關,移動 `HEAD``master` 和 `bugFix` 到目標所示的位置。"
"要完成這一關,移動 `HEAD``main` 和 `bugFix` 到目標所示的位置。"
]
}
}
@ -534,7 +682,7 @@ exports.level = {
"",
"相対リファレンスのよくある使い方としてあるのは、ブランチの移動です。`-f`オプションを使ってブランチを直接コミットに関連付けられます。次のようになります",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"masterブランチを強制的にHEADより親三代前へと移動します。"
]
@ -549,7 +697,7 @@ exports.level = {
"afterMarkdowns": [
"できました!相対リファレンスを使うことで、手短く`C1`を指定することができ、`-f`でブランチを強制的にそこへ移動することができました。"
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -559,7 +707,7 @@ exports.level = {
"markdowns": [
"相対リファレンスとブランチの強制関連付けを見ましたので、いまここでそれらの方法を使ってみましょう。",
"",
"このレベルをクリアするには`HEAD`、`master`、`bugFix`をゴールで指定されている目的位置まで移動してください。"
"このレベルをクリアするには`HEAD`、`main`、`bugFix`をゴールで指定されている目的位置まで移動してください。"
]
}
}
@ -603,9 +751,9 @@ exports.level = {
"",
"Одна из наиболее распространённых целей, для которых используются относительные ссылки - это перемещение веток. Можно напрямую прикрепить ветку к коммиту при помощи опции `-f`. Например, команда:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"Переместит (принудительно) ветку `master` на три родителя назад от `HEAD`."
"Переместит (принудительно) ветку `main` на три родителя назад от `HEAD`."
]
}
},
@ -618,7 +766,7 @@ exports.level = {
"afterMarkdowns": [
"Вуаля! Относительная ссылка дала нам возможность просто сослаться на `C1`, а branch forcing (`-f`) позволил быстро переместить указатель ветки на этот коммит."
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -628,7 +776,7 @@ exports.level = {
"markdowns": [
"Мы рассмотрели относительные ссылки и branch forcing вкупе, так что теперь пришло время пройти следующий уровень.",
"",
"Чтобы пройти этот уровень, передвинь `HEAD`, `master` и `bugFix` так, как показано на визуализации."
"Чтобы пройти этот уровень, передвинь `HEAD`, `main` и `bugFix` так, как показано на визуализации."
]
}
}
@ -672,9 +820,9 @@ exports.level = {
"",
"제가 상대 참조를 사용하는 가장 일반적인 방법은 브랜치를 옮길 때 입니다. `-f` 옵션을 이용해서 브랜치를 특정 커밋에 직접적으로 재지정 할 수 있습니다. 이런 식으로 말이죠:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"(강제로) master 브랜치를 HEAD에서 세번 뒤로 옮겼습니다. (three parents behind HEAD)."
"(강제로) main 브랜치를 HEAD에서 세번 뒤로 옮겼습니다. (three parents behind HEAD)."
]
}
},
@ -686,7 +834,7 @@ exports.level = {
],
"afterMarkdowns": [
"됬네요! 우리는 상대 참조를 통해 `C1`을 간결한 방법으로 참조할 수 있었고 브랜치 강제(`-f`)를 통해 브랜치를 저 위치로 빠르게 옮길 수 있었습니다." ],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -696,7 +844,7 @@ exports.level = {
"markdowns": [
"자 이제 상대 참조와 브랜치 강제의 조합을 봤으니 다음 레벨을 해결해 봅시다.",
"",
"이 레벨을 통과하기 위해서, `HEAD`와 `master`와 `bugFix`를 제시되는 골지점으로 옮겨 주십시오."
"이 레벨을 통과하기 위해서, `HEAD`와 `main`과 `bugFix`를 제시되는 골지점으로 옮겨 주십시오."
]
}
}
@ -740,9 +888,9 @@ exports.level = {
"",
"Один з найуживаніших прийомів де я використовую відносні посилання це переміщення гілок. Ти можеш напряму переспрямувати бранч на якийсь коміт використавши опцію `-f` (force, тобто насильно). Щось на зразок:",
"",
"`git branch -f master HEAD~3`",
"`git branch -f main HEAD~3`",
"",
"Переміщує (насильно) гілку master на три предки позад HEAD."
"Переміщує (насильно) гілку main на три предки позад HEAD."
]
}
},
@ -755,7 +903,7 @@ exports.level = {
"afterMarkdowns": [
"Ось і маєш! Відносні посилання дають нам зручний спосіб доступу до коміту`C1` крім того форсування бранчів (`-f`) дає нам можливість швидко перемістити гілку на цей коміт"
],
"command": "git branch -f master HEAD~3",
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
@ -765,11 +913,218 @@ exports.level = {
"markdowns": [
"Тепер, коли ти побачив відносні посилання та форсування гілок в купі, давай використаємо це щоб пройти поточний рівень.",
"",
"Щоб пройти цей рівень, перемісти `HEAD`, `master` та `bugFix` так як показано в візуалізації."
"Щоб пройти цей рівень, перемісти `HEAD`, `main` та `bugFix` так як показано в візуалізації."
]
}
}
]
},
"vi": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Toán tử \"~\"",
"",
"Giả sử bạn muốn leo lên nhiều cấp trong git. Dùng `^` vài lần thì tù lắm, nên Git đã có dấu ngã (~) cho việc đó.",
"",
"",
"Theo sau toán tử ngã (~) là số lượng cha ông mà bạn muốn leo lên(không bắt buộc). Xem thử làm thật thì thế nào nào"
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Hãy chỉ định số lượng commit với `~`."
],
"afterMarkdowns": [
"BÙUM! Quá chuẩn luôn -- tham chiếu tương đối tuyệt vời."
],
"command": "git checkout HEAD~4",
"beforeCommand": "git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Branch forcing",
"",
"Giờ thì bạn là cao thủ về tham chiếu tương đối rồi, *làm* thật thôi chứ nhỉ.",
"",
"Tôi thì hay thường dùng tham chiếu tương đối để dịch chuyển nhánh. Bạn có thể trực tiếp gán lại nhánh cho commit với cú pháp `-f`. Kiểu như thế này:",
"",
"`git branch -f main HEAD~3`",
"",
"dịch chuyển (ép buộc) nhánh main lên 3 commit phía trên HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Xem thử cái lệnh trên hoạt động sao nào."
],
"afterMarkdowns": [
"Đóóóó! Tham chiếu tương đối cho chúng ta một cách chuẩn xác để trỏ tới `C1` và ép nhánh bằng (`-f`) thì dịch chuyển nhanh chóng nhánh tới đó."
],
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Giờ thì bạn đã thấy cách kết hợp tham chiếu tương đối và ép nhánh, dùng chúng để vượt level tiếp thôi.",
"",
"Để hoàn thành cấp độ này, chuyển `HEAD`, `main`, và `bugFix` đến mục tiêu được xác định của chúng."
]
}
}
]
},
"sl_SI": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Operator \"~\"",
"",
"Recimo, da se želiš premakniti veliko stopenj višje po drevesu commitov. Malo je nerodno večkrat tipkati `^`, zato ima Git tudi tilda (~) operator.",
"",
"",
"Tilda operator (opcijsko) sprejme številko, ki določi, koliko staršev bi se rad povzpel po drevesu. Poglejmo to v praksi."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Določimo število prejšnjih commitov z `~`."
],
"afterMarkdowns": [
"Boom! Tako jedrnato -- relativne reference so super."
],
"command": "git checkout HEAD~4",
"beforeCommand": "git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Forcanje Branchev",
"",
"Sedaj si strokovnjak za relativne reference, zato jih končno *uporabimo* za nekaj.",
"",
"Eden izmed najpogostejših načinov, kjer uporabljam relativne reference je za premikanje branchev naokoli. Direktno lahko premakneš branch na nek commit z `-f` opcijo. Takole nekako:",
"",
"`git branch -f main HEAD~3`",
"",
"premakne (s force-om) main branch tri commite za HEAD."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Poglejmo si prejšnji ukaz v praksi."
],
"afterMarkdowns": [
"Tako ja! Relativne reference so nam dale jedrnat način s katerim se lahko nanašamo na `C1` in branch force-anje (`-f`) nam je omogočilo, da hitro prestavimo branch na to lokacijo."
],
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Sedaj ko smo si pogledali relativne reference in force branchanje v kombinaciji, uporabimo to, da rešimo naslednjo stopnjo.",
"",
"Za dokončanje te stopnje, premakni `HEAD`, `main` in `bugFix` na njihove ciljne prikazane destinacije."
]
}
}
]
},
"pl": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Operator \"~\"",
"",
"Powiedzmy, że chcesz przejść o wiele poziomów wstecz na drzewie commitów. Wielokrotne wpisywanie `^` może być męczące. Na tą okazję Git ma również operator - tyldę (~).",
"",
"",
"Operator tyldy (opcjonalnie) przyjmuje numer porządkowy, który określa liczbę rodziców o ile chcesz się wspiąć. Zobaczmy to w akcji."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Podajmy liczbę commitów, które chcemy przeskoczyć za `~`."
],
"afterMarkdowns": [
"Boom! Tak szybko - referencje względne są czadowe."
],
"command": "git checkout HEAD~4",
"beforeCommand": "git commit; git commit; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Forsowanie branczy",
"",
"Jesteś teraz ekspertem ds. referencji. *Wykorzystajmy* je do czegoś.",
"",
"Jednym z najczęstszych sposobów, w jaki korzystam z referencji względnych, są działania na gałęziach. Możesz bezpośrednio przypisać gałąź do commita za pomocą opcji `-f`. Coś w tym stylu:",
"",
"`git branch -f main HEAD~3`",
"",
"przenosi (na siłę) gałąź `main` trzy commity wstecz za HEADa."
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Sprawdźmy poprzednią komendę w akcji."
],
"afterMarkdowns": [
"Proszę bardzo! Referencje względne umożliwiły w zwięzły sposób, by odnieść się do `C1`, a forsowanie gałęzi (`-f`) pozwoliło na szybkie przeniesienie gałęzi w to konkretne miejsce."
],
"command": "git branch -f main HEAD~3",
"beforeCommand": "git commit; git commit; git commit; git checkout -b bugFix"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"Teraz, gdy poznałeś referencje względne i forsowanie gałęzi w połączeniu, użyj ich do rozwiązania następnego poziomu.",
"",
"Aby ukończyć ten poziom przenieś `HEAD`, `main` oraz `bugFix` do wyświetlonych celów."
]
}
}
]
},
}
};

Some files were not shown because too many files have changed in this diff Show more