diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..5e96f00f --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +learnGitBranching.js.org diff --git a/README.md b/README.md index 25718f42..72a418ba 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ And the following heroes for assisting in translating: * Eroany H Leader ("lhyqy5") * Honorat ("ahonorat") * Vasil Kulakov ("coyl") & Lyubov Agadjanyan ("shayenblue") +* Aliaksei Berkau ("alexeiberkov") 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) diff --git a/package.json b/package.json index 2af25e75..d0216de9 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "react-tools": "^0.13.1" }, "dependencies": { - "backbone": "^1.1.2", + "backbone": "~1.1.2", "events": "^1.0.2", "flux": "^2.0.1", "jquery": "~1.7.3", diff --git a/src/js/__tests__/base.js b/src/js/__tests__/base.js index f408991e..5c8547c8 100644 --- a/src/js/__tests__/base.js +++ b/src/js/__tests__/base.js @@ -84,7 +84,7 @@ var expectTreeAsync = function(command, expectedJSON, startJSON) { console.log(JSON.stringify(getHeadlessSummary(headless))); } return compareAnswer(headless, expectedJSON); - }, 'trees should be equal', 100); + }, 'trees should be equal', 400); }; var expectLevelSolved = function(levelBlob) { diff --git a/src/js/intl/strings.js b/src/js/intl/strings.js index e66b3b0c..3eb08156 100755 --- a/src/js/intl/strings.js +++ b/src/js/intl/strings.js @@ -378,7 +378,9 @@ exports.strings = { /////////////////////////////////////////////////////////////////////////// 'git-warning-hard': { '__desc__': 'One of the warning messages for git', - 'en_US': 'The default behavior is a --hard reset, feel free to omit that option!', + 'en_US': 'The default behavior for resets on LearnGitBranching is a --hard, so feel free to omit ' + + 'that option if you get tired of typing it out in our lessons. Just remember that the default ' + + 'behavior on actual Git is --mixed.', 'de_DE': 'Das Standardverhalten in dieser Demo ist --hard, du kannst die Option auch weglassen!', 'zh_CN': '默认的行为是 --hard 硬重置,尽管省略掉那个选项吧!', 'zh_TW': '預設的行為是 --hard reset,儘量省略掉那個選項吧!', diff --git a/src/js/level/builder.js b/src/js/level/builder.js index 38e33ec0..d3e7b1a2 100644 --- a/src/js/level/builder.js +++ b/src/js/level/builder.js @@ -21,7 +21,6 @@ var MultiView = require('../views/multiView').MultiView; var CanvasTerminalHolder = require('../views').CanvasTerminalHolder; var ConfirmCancelTerminal = require('../views').ConfirmCancelTerminal; var NextLevelConfirm = require('../views').NextLevelConfirm; -var LevelToolbar = require('../views').LevelToolbar; var MarkdownPresenter = require('../views/builderViews').MarkdownPresenter; var MultiViewBuilder = require('../views/builderViews').MultiViewBuilder; @@ -45,6 +44,7 @@ var LevelBuilder = Level.extend({ initialize: function(options) { options = options || {}; options.level = {}; + this.options = options; var locale = LocaleStore.getLocale(); options.level.startDialog = {}; @@ -75,10 +75,6 @@ var LevelBuilder = Level.extend({ }, initName: function() { - this.levelToolbar = new LevelToolbar({ - name: intl.str('level-builder'), - parent: this - }); }, initGoalData: function() { @@ -97,7 +93,6 @@ var LevelBuilder = Level.extend({ this.doBothVis('hide'); this.goalWindowPos = position; this.goalWindowSize = size; - this.levelToolbar.$goalButton.text(intl.str('show-goal-button')); if ($('#goalPlaceholder').is(':visible')) { $('#goalPlaceholder').hide(); this.mainVis.myResize(); diff --git a/src/js/react_views/CommandView.jsx b/src/js/react_views/CommandView.jsx index 529d02cc..362c4a6e 100644 --- a/src/js/react_views/CommandView.jsx +++ b/src/js/react_views/CommandView.jsx @@ -71,7 +71,11 @@ var CommandView = React.createClass({

{'$'} - {' ' + this.state.rawStr} + {' '} + diff --git a/src/js/views/builderViews.js b/src/js/views/builderViews.js index f956e730..bdf41b0e 100644 --- a/src/js/views/builderViews.js +++ b/src/js/views/builderViews.js @@ -75,7 +75,7 @@ var MarkdownGrabber = ContainedBase.extend({ var confirmCancel = new Views.ConfirmCancelView({ deferred: buttonDefer, destination: this.getDestination() - }.bind(this)); + }); } this.updatePreview(); diff --git a/src/js/views/levelDropdownView.js b/src/js/views/levelDropdownView.js index 889dd5fe..8f01aee0 100644 --- a/src/js/views/levelDropdownView.js +++ b/src/js/views/levelDropdownView.js @@ -281,7 +281,6 @@ var LevelDropdownView = ContainedBase.extend({ // also go find the series and update the about _.each(this.seriesViews, function(view) { if (view.levelIDs.indexOf(id) === -1) { - view.resetAbout(); return; } view.updateAboutForLevelID(id); @@ -354,8 +353,7 @@ var SeriesView = BaseView.extend({ template: _.template($('#series-view').html()), events: { 'click div.levelIcon': 'click', - 'mouseenter div.levelIcon': 'enterIcon', - 'mouseleave div.levelIcon': 'leaveIcon' + 'mouseenter div.levelIcon': 'enterIcon' }, initialize: function(options) { @@ -365,7 +363,11 @@ var SeriesView = BaseView.extend({ this.levels = LevelStore.getLevelsInSequence(this.name); this.levelIDs = []; + var firstLevelInfo = null; _.each(this.levels, function(level) { + if (firstLevelInfo === null) { + firstLevelInfo = this.formatLevelAbout(level.id); + } this.levelIDs.push(level.id); }, this); @@ -375,6 +377,7 @@ var SeriesView = BaseView.extend({ this.JSON = { displayName: intl.getIntlKey(this.info, 'displayName'), about: intl.getIntlKey(this.info, 'about') || " ", + levelInfo: firstLevelInfo, ids: this.levelIDs }; @@ -396,13 +399,8 @@ var SeriesView = BaseView.extend({ return $(element).attr('data-id'); }, - resetAbout: function() { - this.$('p.about').text(intl.getIntlKey(this.info, 'about')) - .css('font-style', 'inherit'); - }, - setAbout: function(content) { - this.$('p.about').text(content).css('font-style', 'italic'); + this.$('p.levelInfo').text(content); }, enterIcon: function(ev) { @@ -411,12 +409,19 @@ var SeriesView = BaseView.extend({ }, updateAboutForLevelID: function(id) { - var level = LevelStore.getLevel(id); - this.setAbout(intl.getName(level)); + this.setAbout(this.formatLevelAbout(id)); }, - leaveIcon: function() { - this.resetAbout(); + formatLevelAbout: function(id) { + var level = LevelStore.getLevel(id); + return this.getLevelNumberFromID(id) + + ': ' + + intl.getName(level); + }, + + getLevelNumberFromID: function(id) { + // hack -- parse out the level number from the ID + return id.replace(/[^0-9]/g, ''); }, click: function(ev) { diff --git a/src/levels/remote/fakeTeamwork.js b/src/levels/remote/fakeTeamwork.js index f6db4ba4..5b9a8f38 100644 --- a/src/levels/remote/fakeTeamwork.js +++ b/src/levels/remote/fakeTeamwork.js @@ -10,7 +10,8 @@ exports.level = { "es_AR": "Simulando el trabajo en equipo", "pt_BR": "Simulando trabalho em equipe", "zh_CN": "模拟团队合作", - "zh_TW": "模擬團隊合作" + "zh_TW": "模擬團隊合作", + "ru_RU": "Коллективная работа" }, "hint": { "en_US": "remember you can specify the number of commits to fake", @@ -20,7 +21,8 @@ exports.level = { "es_AR": "Acordate que podés especificar cuántos commits simular", "pt_BR": "Lembre-se que você pode especificar quantos commits quer simular", "zh_CN": "记住为fake中的commit指定数量", - "zh_TW": "你要記得指定要送多少個 commit 出去" + "zh_TW": "你要記得指定要送多少個 commit 出去", + "ru_RU": "помните, Вы можете указать колличество фейковых коммитов" }, "startDialog": { "en_US": { @@ -400,6 +402,60 @@ exports.level = { } } ] + }, + "ru_RU": { + "childViews": [ + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "## Simulating collaboration", + "", + "В данном уроке мы находимся в немного затруднительном положении -- для выполнения ряда упражнений нам нужно обучить Вас как скачивать наработки и изменения, которые были сделаны в удалённом репозитории.", + "", + "Это означает, что нам следует \"сделать вид\", как будто мы знаем о том, что наш удалённый репозиторий, с которым мы работаем, был изменён наработками, сделанными одним из Ваших коллег / друзей / единомышленников. Это может быть какая-то ветка либо же какой-то конкретный коммит.", + "", + "Для того, чтобы добится своих целей, нам предоставляется комманда со звучным именем `git fakeTeamwork`! Имя комманды однозначно даёт понят что она выполняет. Давайте ознакомимся с демо..." + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Поведение комманды `fakeTeamwork` по-умолчанию заключаентся в том, чтобы просто \"инициировать\" коммит на master-е" + ], + "afterMarkdowns": [ + "Ну вот -- удалённый репозиторый был изменён при помощи добавления нового коммита, и мы не ещё не скачали этот коммит, потому что не запустили комманду `git fetch`." + ], + "command": "git fakeTeamwork", + "beforeCommand": "git clone" + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "В данной комманде Вам доступна возможность указать ветку и колличество добавляемых коммитов" + ], + "afterMarkdowns": [ + "С помощью одной лишь комманды мы симулируем добавление трёх коммитов в ветку `foo` на удалённом репозитории" + ], + "command": "git fakeTeamwork foo 3", + "beforeCommand": "git branch foo; git clone" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Последующие уровни будут довольно сложными, поэтому в этом упражнении от Вас больше ничего не требуется.", + "", + "Вперёд! Склонируйте удалённый репозиторий (с помощью `git clone`), симулируйте какие-нибудь изменения на этом удалённом репозитории, сделайте какие-нибудь свои коммиты и затем скачайте \"чужие\" изменения. Это выглядит как несколько уроков в одном!" + ] + } + } + ] } } }; diff --git a/src/levels/remote/fetchRebase.js b/src/levels/remote/fetchRebase.js index b6f4beca..8b14dbc0 100644 --- a/src/levels/remote/fetchRebase.js +++ b/src/levels/remote/fetchRebase.js @@ -10,7 +10,8 @@ exports.level = { "pt_BR": "Histórico divergente", "de_DE": "Abweichende History", "fr_FR": "Historique divergent", - "ja" : "履歴の分岐" + "ja" : "履歴の分岐", + "ru_RU": "Расхождение в истории" }, "hint": { "en_US": "check out the ordering from the goal visualization", @@ -20,7 +21,8 @@ exports.level = { "ot_BR": "Preste atenção na ordem da visualização do objetivo", "de_DE": "Beachte die Reihenfolge in der Zieldarstellung", "ja" : "ゴールのビジュアライズの順番を参照", - "fr_FR": "regardez l'ordre dans la fenêtre de visualisation d'objectif" + "fr_FR": "regardez l'ordre dans la fenêtre de visualisation d'objectif", + "ru_RU": "проверьте сортировку в визуализации цели" }, "startDialog": { "en_US": { @@ -1023,6 +1025,149 @@ exports.level = { } } ] + }, + "ru_RU": { + "childViews": [ + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "## Когда наработки расходятся", + "", + "Вот мы и познакомились с тем, как забирать (`pull`) чужие коммиты и как закачивать (`push`) свои наработки и изменения. Выглядит всё довольно просто, и не ясно какие же могу возникать у людей трудности со всем этим ?", + "", + "Сложности возникают тогда, когда история репозитория *расходится*. Давайте посмотрим на пример прежде чем идти дальше...", + "" + ] + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Представьте себе, Вы склонировали репозиторий в понедельник и начали разрабатывать какую-то новую и уникальную часть приложения (на сленге разработчиков - `фича`). В пятницу вечером Вы наконец-то готовы опубликовать Вашу фичу. Но, о нет! Ваш коллега в течении недели написал кучу кода, который делает все Ваши наработки устарелыми. Этот код был также закоммичен и опубликован на общедоступном удалённом репозитории, поэтому теперь *Ваш* код базируется на *устаревшей* версии проект и более не уместен.", + "", + "В этому случае использование комманды `git push` является сомнительным. Как поведёт себя комманда `git push` если Вы её выполните ? Может быть она изменит удалённый репозиторий и вернёт всё к тому состоянию, которое было в понедельник ? А может быть комманда попробует добавить Ваш код, не удаляя при этом новый? Или же она проигнорирует Ваши изменения, так как они уже устарели?", + "", + "По причине того, что в данной ситуации (когда история расходится) слишком много двусмысленностей и неопределённостей, git не даст Вам закачать (`push`) Ваши изменения. Чтобы поделится и закачать свои наработки, git будет принуждать Вас включить в состав своей работы все те последние наработки и изменения, находящиеся на удалённом репозитории." + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Слишком много болтавни! Давайте посмотрим, как всё работает на живом примере" + ], + "afterMarkdowns": [ + "Видите? Ничего не произошло. Всё потому, что комманда `git push` не выполнилась успешно. Дело в том, что Ваш последний коммит `C3` основан на удалённом коммите `C1`. В свою очередь удалённый репозиторий уже изменился под воздействием `C2`. Вот почему git отклонил Ваш push." + ], + "command": "git push", + "beforeCommand": "git clone; git fakeTeamwork; git commit" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Как же разрешит данную ситуацию? Всё очень просто! Всё что Вам нужно - перебазировать свою работу на наиболее последнюю версию удалённой ветки.", + "", + "Существует множество путей, как сделать это, но наиболее простой способ 'сдвинуть' свои наработки - через пребазировку или rebasing. Давайте посмотрим, как это выглядит." + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Теперь, когда мы сперва перебазиуемся прежде чем публиковать изменения..." + ], + "afterMarkdowns": [ + "Опа! Мы только что обновили наш локальный образ удалённого репозитория средствами `git fetch`. Ещё мы перебазировали наши наработки, чтобы они отражали все изменения с удалённого репозитория, и опубликовали их с помощью `git push`" + ], + "command": "git fetch; git rebase o/master; git push", + "beforeCommand": "git clone; git fakeTeamwork; git commit" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "А есть ещё какие-либо варианты чтобы обновить мои наработки, к тому моменту как удалённый репозиторий был обновлён? Конечно есть! Давайте ознакомимся с парочкой новых штучек, но в этот раз с помощью комманды `merge`.", + "", + "Не смотря на то, что `git merge` не передвигает ваши наработки (а всего лишь создаёт новый коммит, в котором Ваши и удалённые изменения объеденены), этот способ помогает указать git-у на то, что Вы собираетесь включить в состав Ваших наработок все изменения с удалённого репозитория. Это значит, что Ваш коммит отразится на всех коммитах удалённой ветки, поскольку удалённая ветка является *предком* Вашей собственной локальной ветки.", + "", + "Давайте взглянем на демонстрацию..." + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Таким образм если мы объеденим (merge) вместо перебазирования (rebase)..." + ], + "afterMarkdowns": [ + "Опа! Мы обновили наше локальное представление удалённого репозитория с помощью `git fetch`, *объединили* Ваши новые наработки с нашими наработками (чтобы отразить изменения в удалённом репозитории), и затем опубликовали их с помощью `git push`" + ], + "command": "git fetch; git merge o/master; git push", + "beforeCommand": "git clone; git fakeTeamwork; git commit" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Здорово! А можно ли как-то зделать всё тоже самое, но с меньшим количеством комманд?", + "", + "Конечно -- ведь Вы уже знаете комманду `git pull`, которая является аналогом и более кратким аналогом для совместных fetch и merge. А команда `git pull --rebase` - аналог для совместно вызванных fetch и rebase!", + "", + "Давайте взглянем на эти оба варианта." + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Сперва - с флагом `--rebase`..." + ], + "afterMarkdowns": [ + "Тот же результат как и ранее, но намного короче вызов команд." + ], + "command": "git pull --rebase; git push", + "beforeCommand": "git clone; git fakeTeamwork; git commit" + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "А теперь с обычным `pull`" + ], + "afterMarkdowns": [ + "И снова - результат такой же, как и ранее!" + ], + "command": "git pull; git push", + "beforeCommand": "git clone; git fakeTeamwork; git commit" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Рабочий процесс получения изменений (fetching), перебазирования/объединения (rebase/merging) и публикации изменений (pushing) довольно часто используемый. В последующий уроках мы изучим более сложные варианты этих рабочих процессов, но пока что, давайте остановимся на том, что есть.", + "", + "Выполните следующее, чтобы выполнить задание уровня:", + "", + "* Склонируйте репозиторий", + "* Сфабрикуйте командную работу (1 коммит)", + "* Сделайте свой собственный коммит (1 commit)", + "* Опубликуйте свои наработки посредствам *перебазировки rebasing*" + ] + } + } + ] } } }; diff --git a/src/levels/remote/pull.js b/src/levels/remote/pull.js index 121d0d69..1aa99a09 100644 --- a/src/levels/remote/pull.js +++ b/src/levels/remote/pull.js @@ -10,7 +10,8 @@ exports.level = { "pt_BR": "Git Pull", "de_DE": "Git Pull", "ja" : "Git Pull", - "fr_FR": "Git pull" + "fr_FR": "Git pull", + "ru_RU": "Git pull" }, "hint": { "en_US": "Just run git pull!", @@ -20,7 +21,8 @@ exports.level = { "pt_BR": "Basta executar git pull!", "de_DE": "Führe einfach git pull aus.", "ja" : "単にgit pullを実行!", - "fr_FR": "Utilisez facilement git pull !" + "fr_FR": "Utilisez facilement git pull !", + "ru_RU": "Запустите комманду git pull !" }, "startDialog": { "en_US": { @@ -435,6 +437,65 @@ exports.level = { } } ] - } + }, + "ru_RU": { + "childViews": [ + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "## Git Pull", + "", + "Теперь, когда мы познакомились с тем, как извлекать данные из удалённого репозитория с помощью `git fetch`, давайте обновим нашу работу чтобы отобразить все эти изменения!", + "", + "Существует множество вариантов решений -- как только у вас имеется локальный коммит, Вы можете соединить его с другой веткой. Это значит Вы можете выполнить одну из комманд:", + "", + "* `git cherry-pick o/master`", + "* `git rebase o/master`", + "* `git merge o/master`", + "* и т.д.", + "", + "По факту процедура *скачивания (fetching)* изменений с удалённой ветки и *объединения (merging)* настолько частая и распространённая, что git предоставляет вместо двух команд - одну! Эта команда - `git pull`." + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Давайте рассмотрим, как `fetch` и `merge` выполняются последовательно" + ], + "afterMarkdowns": [ + "Опа -- мы скачали `C3` с помощью команды `fetch` и затем объединяем эти наработки с помощью `git merge o/master`. Теперь наша ветка `master` отображает изменения с удалённого репозитория (в данном случае с репозитория `origin`)" + ], + "command": "git fetch; git merge o/master", + "beforeCommand": "git clone; git commit; git fakeTeamwork" + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Что же произойдёт если вместо этих команд мы воспользуемся `git pull` ?" + ], + "afterMarkdowns": [ + "Абсолютно тоже самое! Нужно ясно и чётко понимать, что `git pull` существенно уменьшает Вашу рутинную работу, если бы Вы использовали `git fetch` и последующее слияние (merging) скаченной ветки." + ], + "command": "git pull", + "beforeCommand": "git clone; git commit; git fakeTeamwork" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Мы изучим детали комманды `git pull` чуть позже (включая опции и аргументы вызова команды), а пока что давайте просто попробуем эту комманду.", + "", + "Помните -- мы также можете выполнить этот уровень с помощью комманд `fetch` и `merge`, но нужно ли делать так, когда можно воспользоваться всего-лишь одной коммандой ? :P" + ] + } + } + ] + } } }; diff --git a/src/levels/remote/push.js b/src/levels/remote/push.js index 3e035955..e26e8aac 100644 --- a/src/levels/remote/push.js +++ b/src/levels/remote/push.js @@ -10,7 +10,8 @@ exports.level = { "pt_BR": "Git Push", "de_DE": "Git Push", "ja" : "Git Push", - "fr_FR": "Git push" + "fr_FR": "Git push", + "ru_RU": "Git push" }, "hint": { "en_US": "Remember you have to clone before you can push!", @@ -20,7 +21,8 @@ exports.level = { "pt_BR": "Lembre-se de clonar antes de fazer o push!", "de_DE": "Denk dran, dass du einen Clone brauchst bevor du Pushen kannst!", "ja" : "Pushできる前にまずリポジトリをcloneする必要があるのをお忘れなく", - "fr_FR": "Rappelez-vous que vous devez cloner avant de pouvoir faire un push !" + "fr_FR": "Rappelez-vous que vous devez cloner avant de pouvoir faire un push !", + "ru_RU": "Помните, что прежде чем push-ить вам нужно сколнировать репозиторий!" }, "startDialog": { "en_US": { @@ -315,6 +317,49 @@ exports.level = { } } ] + }, + "ru_RU": { + "childViews": [ + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "## Git Push", + "", + "Хорошо, мы скачали изменения с удалённого репозитория и включили их в наши локальные наработки. Всё это замечательно, но, как нам поделиться _своими_ наработками и изменениями с другими участниками проекта?", + "", + "Способ, которым мы воспользуемся, является противоположным тому способу, которым мы пользовались ранее для скачивания наработок (`git pull`). Этот способ - использование комманды `git push`!", + "", + "Комманда `git push` отвечает за загрузку _Ваших_ изменений в указанный удалённый репозиторий, а также включение Ваших коммитов в состав удалённого репозитория. По окончанию работы комманды `git push` все Ваши друзья смогут скачать себе все сделанные Вами наработки.", + "", + "Вы можете рассматривать комманду `git push` как \"публикацию\" своей работы. Эта комманда скрывает в себе множество тонкостей и ньюансов, с которыми мы познакомимся в ближайшее время, а пока что давайте начнём с малого...", + "", + "*замечание -- поведение комманды `git push` без аргументов варьируется в зависимости он значения `push.default`,указанной в настройках git-а. Значение по-умолчанию зависит от версии git, которую Вы используете, однако в наших уроках мы будем использовать значение `upstream`. Лучше всегда проверят эту опцию прежде чем push-ить Ваши настоящие проекты.*" + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Здесь у нас имеются изменения, которых нету в удалённом репозитории. Давайте же закачаем их туда!" + ], + "afterMarkdowns": [ + "Вот так -- удалённый репозиторий получил новый коммит `C2`, ветка `master` на удалённом репозитории теперь указывает на `C2`, и наше *собственное* локальное отображение удалённого репозитория (`o/master`) изменилось соответственно. Всё синхронизировалось!" + ], + "command": "git push", + "beforeCommand": "git clone; git commit" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Чтобы выполнить задачу этого упражнения, просто поделитесь своими двумя новыми коммитами с удалённым репозиторием. Соберитесь, потому что все последующие уроки будут намного сложнее предыдущих!" + ] + } + } + ] } } }; diff --git a/src/levels/remote/pushArgs.js b/src/levels/remote/pushArgs.js index 58fb68e7..002bf106 100644 --- a/src/levels/remote/pushArgs.js +++ b/src/levels/remote/pushArgs.js @@ -92,7 +92,10 @@ exports.level = { "type": "ModalAlert", "options": { "markdowns": [ - "Ok, for this level let's update both `foo` and `master` on the remote. The twist is that `git checkout` is disabled for this level!" + "Ok, for this level let's update both `foo` and `master` on the remote. The twist is that `git checkout` is disabled for this level!", + "", + "*Note: The remote branches are labeled with `o/` prefixes because the full `origin/` label does not fit in our UI. Don't worry ", + "about this... simply use `origin` as the name of the remote like normal.*" ] } } diff --git a/src/levels/remote/pushManyFeatures.js b/src/levels/remote/pushManyFeatures.js index d10abd43..6f2b0a72 100644 --- a/src/levels/remote/pushManyFeatures.js +++ b/src/levels/remote/pushManyFeatures.js @@ -10,7 +10,8 @@ exports.level = { "pt_BR": "Lembre-se que você sempre pode usar undo ou reset", "de_DE": "Denk dran, du kannst immer undo oder reset benutzen, um deine Befehle zurück zu nehmen.", "ja" : "undoやresetコマンドをいつでも使用することができるのをお忘れなく", - "fr_FR": "Rappelez-vous que vous pouvez toujours utiliser les commandes undo et reset." + "fr_FR": "Rappelez-vous que vous pouvez toujours utiliser les commandes undo et reset.", + "ru_RU": "Помни - ты всегда можешь отменить комманды с помощью undo или reset" }, "name": { "en_US": "Push Master!", @@ -20,7 +21,8 @@ exports.level = { "pt_BR": "Push Master!", "de_DE": "Push Master!", "ja": "Push Master!", - "fr_FR": "Maître du push !" + "fr_FR": "Maître du push !", + "ru_RU": "Push Мастер!" }, "compareOnlyMasterHashAgnostic": true, "startDialog": { @@ -394,6 +396,59 @@ exports.level = { } } ] + }, + "ru_RU": { + "childViews": [ + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "## Слияние фича-бранчей (веток)", + "", + "Теперь, когда Вы умело владеете коммандами fetch, pull и push давайте применим эти навыки в сочетании с новым рабочим процессом (он же workflow).", + "", + "Для разработчиков, вовлечённых в большой проект, является довольно распространённым выполнять всё свою работу на так называемых фича-бранчах (вне `master`). А затем, как только работа выполнена, разработчик интегрирует всё что было им сделано. Всё это, за исключением одного шага, довольно похоже на предыдущий урок (там, где мы закачивали ветки на удалённый репозиторий)", + "", + "Ряд разработчиков делают push и pull лишь на локальную ветку `master` -- таким образом ветка `master` всегда обновлена с тем, что находится на удалённом репозитории (`o/master`).", + "", + "Для этого рабочего процесса мы совместили две вещи:", + "", + "* интеграция фича-бранчей в `master`, а также ", + "* закачку (push) и скачку (pull) с удалённого репозитория" + ] + } + }, + { + "type": "GitDemonstrationView", + "options": { + "beforeMarkdowns": [ + "Давайте быстренько вспомним, как нам обновить `master` и закачать выполненную работу." + ], + "afterMarkdowns": [ + "Здесь мы выполнили две комманды, которые:", + "", + "* перебазировали нашу работу на новенький коммит, пришедший с удалённого репозитория, и", + "* закачали свои наработки в удалённый репозиторий" + ], + "command": "git pull --rebase; git push", + "beforeCommand": "git clone; git commit; git fakeTeamwork" + } + }, + { + "type": "ModalAlert", + "options": { + "markdowns": [ + "Текущая задача является достаточно обильной -- здесь представлена общая схема выполнения:", + "", + "* Есть три фича-бранчи (фича-ветки) -- `side1` `side2` и `side3`", + "* Нам необходимо закачать каждую из них по очереди на удалённый репозиторий", + "* При этом удалённый репозиторий хранит в себе какие-то наработки, которые также следует скачать к себе", + "", + ":O Сложно! Желаю Вам удачи в выполнении этой непростой задачи." + ] + } + } + ] } } }; diff --git a/src/style/main.css b/src/style/main.css index 18da8cba..d6d283d7 100644 --- a/src/style/main.css +++ b/src/style/main.css @@ -865,6 +865,7 @@ div.displayName h3 { div.iconHolder { } +div.seriesView p.levelInfo, div.seriesView p.about { margin: 0px; padding: 4px; @@ -872,6 +873,10 @@ div.seriesView p.about { color: #CCC; } +div.seriesView p.levelInfo { + font-style: italic; +} + div.levelIcon { height: 40px; width: 40px; diff --git a/src/template.index.html b/src/template.index.html index 4c8458e6..f33306f0 100644 --- a/src/template.index.html +++ b/src/template.index.html @@ -222,6 +222,9 @@

<%= about %>

+

+ <%= levelInfo %> +

<% for (var i = 0; i < ids.length; i++) { %>