Мирно жил с Mercurial, но Hg-Git при push запорол сначала инфо о ветке, а потом и вовсе потерял коммит, поэтому пришлось все-таки взяться за Git. Ниже приводятся заметки на полях
книжки, не всегда следующие ее тексту. Заметки будут потихоньку дополняться по мере чтения.
И полезная табличка:
http://mercurial.selenic.com/wiki/GitConcepts настройка
Глобальные настройки:
HG: vi ~/.hgrc
GIT: vi ~/.gitconfig или git config --global foo.bar quux
Настройки репозитория:
HG: vi .hg/hgrc
GIT: vi .git/config или git config foo.bar quux
add
Mercurial коммитит изменения прямо из рабочего каталога, Git - из промежуточного (staging), поэтому их надо явным образом копировать из рабочего в промежуточный между последней правкой и коммитом.
HG: hg init; echo a > foo.txt; hg add foo.txt; echo b > foo.txt; hg commit -m init
В репозитории будет foo.txt с текстом "b".
GIT: git init; echo a > foo.txt; git add foo.txt; echo b > foo.txt; git commit -m init
В репозитории будет foo.txt с текстом "a".
См.
http://git-scm.com/book/en/Git-Basics-Recording-Changes-to-the-Repository .gitignore
HG: можно на лету переключать синтаксис между regex и glob.
GIT: только glob.
CLI
HG: понимает достаточный набор букв для идентификации команды + встроенные псевдонимы (commit = com = ci).
GIT: требует, чтобы команду написали полностью (хотя бы и через автодополнение).
status
HG: working → repo
GIT: working → staging → repo
Файл может быть дважды упомянут в разных разделах: "to be committed" (staging vs repo) и "changed but not updated" (working vs staging).
diff
HG: hg diff
GIT: git diff (changed but not yet staged); git diff --staged (staged but not yet committed)
commit
Быстрая фиксация изменений в ранее добавленном файле:
HG: echo a > foo.txt; hg commit
GIT: echo a > foo.txt; git commit -a
Через staging:
HG: -
GIT: echo a > foo.txt; git add foo.txt; git commit
remove
Удалить файл из working, а при коммите и из репозитория:
HG: hg rm foo.txt; hg commit
GIT: git rm foo.txt; git commit
Удалить файл из staging/repo, но не трогать в working:
HG: hg forget foo.txt; [hg commit]
GIT: git rm --cached foo.txt; [git commit]
move
HG: hg mv a b
GIT: git mv a b
Но есть важная разница: Mercurial в момент коммита
сохраняет в changeset'е информацию о копировании файла (и переименовании как частном случае, т.е. hg mv a b = hg cp a b; hg rm a), а Git тупо удаляет старый файл и добавляет новый, при этом рвёт историю и угадывает переименование уже post factum (напр., при слиянии веток). Поэтому Git потенциально может доставить больше головной боли.
log
Практически одинаково, включая опции --stat, -p (HG: -p,--patch; GIT: -p). У обоих всякие фишечки, которые я и в Hg не использую (а напрасно). В частности, обе системы дают мощные инструменты фильтрации. По форматированию (см.
для Hg):
HG: hg log --template '{node|short} - {author|person}, {date|age} : {desc}\n'
GIT: git log --pretty=format:"%h - %an, %ar : %s"
Ну и, собственно:
HG: hg log --graph --style compact
GIT: git log --graph --pretty=short
Undoing things
В случае ошибки, обнаруженной сразу после коммита, обе системы позволяют удалить последний коммит и добавить новый вместо него. При этом хэш меняется в любом случае.
Исправляем ошибку в описании последнего коммита:
HG: hg commit -m foo; hg commit --amend -m bar
GIT: git commit -m foo; git commit --amend -m bar
Исправляем файл в последнем коммите:
HG: echo a > foo.txt; hg commit; echo b > foo.txt; hg commit --amend
GIT: echo a > foo.txt; git commit -a; echo b > foo.txt; git commit -a --amend (не забыть commit -a / add)
Если файл из working случайно добавлен в staging:
HG: -
GIT: git reset HEAD foo.txt
Сброс локальных изменений в файле до ранее закоммиченного состояния:
HG: hg revert foo.txt
GIT: git checkout -- foo.txt
Remotes
В Git под "remote" подразумевается удаленный репозиторий. Ессно, их может быть много. Информация о каждом хранится в .git/config как отдельная секция ini-файла. В Mercurial они перечисляются в виде название=путь в секции "paths".
HG: hg paths
GIT: git remote -v
Можно посмотреть детальную информацию о конкретном remote (в Mercurial это только путь к нему):
HG: hg paths default
GIT: git remote show origin
При клонировании (hg clone/git clone) исходный репозиторий автоматически запоминается как "default" (в Mercurial) или "origin" (в Git).
Работа с ними одинакова:
HG: hg pull john; hg push default
GIT: git fetch john; git push origin
Управление списком удаленных репозиториев через CLI есть только в Git:
HG: -
GIT: git remote add [shortname] [url]
GIT: git remote rename johnconnor john
GIT: git remote rm john
pull
Получить:
HG: hg pull
GIT: git fetch
Получить и обновить/смержить:
HG: hg pull --update
GIT: git pull
push
HG: hg push
GIT: git push
Конкретный удаленный репозиторий и конкретная ветка:
HG: hg push default -b default
GIT: git push origin master
tags
В Mercurial есть метки (tags) одного типа. Хранятся в текстовом файле .hgtags как пары ревизия/метка. Их можно добавлять туда вручную или через CLI; во втором случае это оформляется как коммит.
В Git есть lightweight tags (хранятся как .git/refs/tags/имя_метки - и хэш ревизии в теле файла), а также annotated tags (хранятся как отдельные объекты). Предполагается работа через CLI. В обоих случаях при добавлении метки коммит не создается. Соответственно, установить источник и время появления "простой" метки невозможно(?).
Список меток:
HG: hg tags
GIT: git tag
Создание метки:
HG: hg tag v0.1
GIT: git tag v0.1
GIT: git tag v0.1 -a -m "tag annotation"
Особенности Git:
1. Поскольку аннотированные метки содержат данные, которые невозможно посмотреть через git tag, следует использовать git show v0.1.
2. Поскольку метки хранятся отдельно от кода, их нужно отправлять в удаленный репозиторий явным образом: git push origin v0.1 (конкретная метка) или git push origin --tags (все метки). При клонировании репозитория все метки оттуда выгребаются в клон автоматически.
Так, ладно, тут адски неудобно конспектировать. Переношу в файлик в ReStructuredText, мб потом где-нибудь выложу результат.