Comments 62
хорошая шпаргалка, спасибо
+5
Вы можете запускать многие команды (такие, как git diff, git blame и т.д.) с флагом "-w" и Git будет просто игнорировать все изменения, связанные с пробельными символами (пробел, табуляция и другие).Чёрт, для языка программирования Whitespace такая опция не подойдёт :-(
+3
У меня есть давний вопрос по гиту, но никто на него не может толком ответить. Предположим, у нас есть какой-то коммит. И стопочка тегов. Хочется узнать, между какими двумя тегами находится коммит. Как?
Тривиальная задача: понять, в какую версию попало изменение в первый раз. Но каждый раз сталкиваюсь с задачей — и каждый раз в ход идут какие-то ужасные хаки с перебором и т.д.
Тривиальная задача: понять, в какую версию попало изменение в первый раз. Но каждый раз сталкиваюсь с задачей — и каждый раз в ход идут какие-то ужасные хаки с перебором и т.д.
0
А если как-нибудь вот так вот попробовать?
git log {{commit-hash}}.. --reverse --oneline --decorate | grep 'tag: ' | head -1
+1
git describe
и
git describe --contains
?+35
git describe --abbrev=0 --tags Но похоже выше уже дали наводку :)
+1
4. Просмотр ещё не влитых в родительскую ветку изменений
Я обычно смотрю какие ветки не были влиты в master:
git fetch origin
git branch -a --no-merged origin/master
+2
Это совсем другой вопрос: 14. Поиск и удаление старых веток :)
0
По пункту 4: вместо git log --no-merges удобно использовать команду git cherry — она сравнивает коммиты по изменениям и, следовательно, «прокуривает» ситуацию, когда был сделан cherry-pick из одной ветки в другую.
По пункту 11: Meld восхитителен — он гораздо лучше самого git'а понимает различные конфликтные ситуации и простые разруливает самостоятельно. В более сложных ситуациях он упрощает понимание того, что было сделано, так как показывает сразу три варианта — как было до того, как ветки разошлись, как стало в ветке А и как стало в ветке Б. Ну и всякие команды, которые быстро переносят результаты из веток в нужном порядке (типа «здесь берём оба варианта, но из ветки А идёт первым, а из Б — следом за ним»). Одна беда — на маке Meld неюзабелен.
По пункту 11: Meld восхитителен — он гораздо лучше самого git'а понимает различные конфликтные ситуации и простые разруливает самостоятельно. В более сложных ситуациях он упрощает понимание того, что было сделано, так как показывает сразу три варианта — как было до того, как ветки разошлись, как стало в ветке А и как стало в ветке Б. Ну и всякие команды, которые быстро переносят результаты из веток в нужном порядке (типа «здесь берём оба варианта, но из ветки А идёт первым, а из Б — следом за ним»). Одна беда — на маке Meld неюзабелен.
+2
Под Mac OS X есть чудесный и волшебный Kaleidoscope.
0
Использую diffuse вместо meld. Он намного шустрее, но не умеет сравнивать директории. На маке вполне юзабелен, только надо что-то сделать с сочетаниями клавиш ctrl+стрелки, которые на маке привязаны на какие-то действия (можно перенастроить).
Для мёржа настроил diffuse в четыре колонки:
Для мёржа настроил diffuse в четыре колонки:
[merge]
tool = diffuse_
[mergetool "diffuse_"]
cmd = diffuse \"$LOCAL\" \"$BASE\" \"$REMOTE\" \"$MERGED\"
0
Под винду мне очень понравился Beyond Compare, правда я давно им пользовался, не знаю, что там в последних версиях.
+1
UFO just landed and posted this here
Согласен. Однако, зачем, например, покупать PyCharm при наличии бесплатных альтернатив (vim, например)? :)
0
UFO just landed and posted this here
Он же только двухстороннее сравнение делает?
+1
Большую часть команд `git log` для меня заменил `tig`. habrahabr.ru/post/206606
+7
Спасибо! Про reflog можно ещё немного написать бы, чтобы знали, что и такое бывает и иногда выручает.
+2
По поводу текстов коммитов:
Автор оригинала предлагает заканчивать фразу When applied this commit will... В статье, на которую он сам ссылается, предлагается писать императивом chris.beams.io/posts/git-commit/#imperative
Для английского противоречий нет, так как форма When applied this commit will...Fix some bugs идентична императиву Fix some bugs
В русском же эти формы разные. Не думаю, правда, что многие люди пишут коммит-месседжи на русском
Автор оригинала предлагает заканчивать фразу When applied this commit will... В статье, на которую он сам ссылается, предлагается писать императивом chris.beams.io/posts/git-commit/#imperative
Для английского противоречий нет, так как форма When applied this commit will...Fix some bugs идентична императиву Fix some bugs
В русском же эти формы разные. Не думаю, правда, что многие люди пишут коммит-месседжи на русском
+4
Мы пишем на русском. У нас принята форма ответа на вопрос «Что было сделано?» (например: «Реализовано то-то» или «Исправлена ошибка такая-то»). Это удобно, когда прибегает менеджер и, бешено вращая глазами, требует срочно предоставить список, того, что мы сделали за неделю/месяц/в этом релизе. git log, минимальные правки, копипаст в письмо и можно программировать дальше.
+2
Добавлю про --amend
Бывает, что нужно исправить опечатку в комментарии к последнему коммиту, не затрагивая файлов. В этом случае удобно воспользоваться флагом
Бывает, что нужно исправить опечатку в комментарии к последнему коммиту, не затрагивая файлов. В этом случае удобно воспользоваться флагом
allow-empty
, чтобы гит не ругался на отсутствие изменений для коммита:git commit --amend --allow-empty -m "New commit message"
+6
Еще там удобно использовать "--no-edit", тогда используется коммент от коммита, и его не нужно писать заново.
+2
У меня, кажется, без --allow-empty такая конструкция прокатывает.
Просто вызываю стрелочкой вверх последний коммит из истории, правлю сообщение и в конец дописываю --amend.
Пример:
Просто вызываю стрелочкой вверх последний коммит из истории, правлю сообщение и в конец дописываю --amend.
Пример:
nickolaus@nicknout:~/CHAS-CORRECT/correct$ git add chrome/dictionary.js
nickolaus@nicknout:~/CHAS-CORRECT/correct$ git commit -m "Bred"
[master b145062] Bred
1 file changed, 1 insertion(+), 1 deletion(-)
nickolaus@nicknout:~/CHAS-CORRECT/correct$ git commit -m "В словарь" --amend
[master b80d697] В словарь
1 file changed, 1 insertion(+), 1 deletion(-)
nickolaus@nicknout:~/CHAS-CORRECT/correct$
+3
«Хорошие примечания к коммиту»
Я пишу комментарии в порядке добавления файлов, например, следующим образом:
1. common/modules/delivery/components/classes/HTTPRequestAdapter: инициализация параметров curl перенесена в конструктор + отлажен механизм отправки
2. common/modules/delivery/components/classes/cdek/CDEKAdapter: убран неиспользуемый метод форматирования даты
Думаю такие комменты читать команде проекта, да мне самому удобнее
Я пишу комментарии в порядке добавления файлов, например, следующим образом:
1. common/modules/delivery/components/classes/HTTPRequestAdapter: инициализация параметров curl перенесена в конструктор + отлажен механизм отправки
2. common/modules/delivery/components/classes/cdek/CDEKAdapter: убран неиспользуемый метод форматирования даты
Думаю такие комменты читать команде проекта, да мне самому удобнее
0
Не совсем понял, обе строчки идут в один коммит? Если да, то это странно, суда по комментариям, это должны быть разные коммиты. А писать в коммите, какие файлы были затронуты — тоже странно, всегда можно посмотреть лог коммитов для конкретного файла с помощью git log, если хочется понять кто и зачем трогал файл.
+8
«Если я хочу отменить все внесённые изменения и начать работу с чистого листа, я использую команду git reset --hard HEAD (самый частый случай).»
Достаточно `git reset --hard`
«Если я просто хочу взять три последних коммита и слить их в один большой коммит, я использую команду git reset --soft {{some-start-point-hash}}.»
Лучше использовать `git rebase -i HEAD~3`. И про `reflog` можно добавить — обязательно пригодится, когда произойдёт неправильное использование `git rebase`
Достаточно `git reset --hard`
«Если я просто хочу взять три последних коммита и слить их в один большой коммит, я использую команду git reset --soft {{some-start-point-hash}}.»
Лучше использовать `git rebase -i HEAD~3`. И про `reflog` можно добавить — обязательно пригодится, когда произойдёт неправильное использование `git rebase`
+1
Недавно узнал способ именовать stash, чтобы потом можно было по его описанию понять, что там такое:
git stash save something something
+6
Не делайте ребейз коммитов, находящиеся вне вашего репозитория.
Вот давно хотел спросить, что это значит? не делать rebase c удаленной ветки не своего репозитория?
0
те кто себе сделают git pull «отребейзенной» (ну и словечко) ветки получат пачку конфликтов из-за того что их история коммитов начнет отличаться от той, которая будет лежать в репозитории
0
При ребейзе часть коммитов пересоздаётся — при этом ломается история.
Т.е. «не делайте такого ребейза, который приведёт к изменению коммитов, сделанных не вами».
Т.е. «не делайте такого ребейза, который приведёт к изменению коммитов, сделанных не вами».
0
Точнее сказать, опубликованны. Т. к. свои опубликованные коммиты лучше не ребейзить, чтобы тот, кто уже коммитил что-то основанное на них, не страдал.
0
Тоже с таким сталкивался. На самом деле особой проблемы нет.
В этом случае проблем не будет.
Предположим в мастере у вас 3 коммита:
master:
Разработчик бранчуется от C и добавляет свои 2 коммита:
feature:
Потом мы делаем rebase master HEAD~2. Страшно даже подумать, у-у-у-у… Что получаем?
С точки зрения git коммиты B и B' разные, так как у них разные хэши. При попытке сделать git rebase master (без -i) git попытатеся применить коммит B на B' и C', что, естественно, вызовет конфликт. Однако разработчик должен четко понимать, что он с коммитами B и C не работал и они его вообще никак не волнуют. Потому при git rebase -i master он должен пропустить B и C.
В результате после rebase разработчик получит:
- Всегда делайте только интерактивный rebase
- Внимательно изучайте список коммитов, который предлагается к применению
- Пропускайте (skip) те коммиты, которые делали не вы
В этом случае проблем не будет.
Предположим в мастере у вас 3 коммита:
master:
A---B---C
Разработчик бранчуется от C и добавляет свои 2 коммита:
feature:
A---B---C
\
D---E
Потом мы делаем rebase master HEAD~2. Страшно даже подумать, у-у-у-у… Что получаем?
A---B'---C'
\
B---C---D---E
С точки зрения git коммиты B и B' разные, так как у них разные хэши. При попытке сделать git rebase master (без -i) git попытатеся применить коммит B на B' и C', что, естественно, вызовет конфликт. Однако разработчик должен четко понимать, что он с коммитами B и C не работал и они его вообще никак не волнуют. Потому при git rebase -i master он должен пропустить B и C.
В результате после rebase разработчик получит:
A---B'---C'
\
D---E
+2
Вообще‐то git при rebase автоматически пропускает уже применённые изменения, даже если они были применены в других (или как часть других) commit’ов. Конфликты иногда будут, если там ещё что‐то рядом меняли, но rebase --interactive вам здесь поможет, только если вы прочитали все сделанные другими разработчиками изменения.
Я с rebase работаю всегда в одном из двух режимов: histedit — меняю историю, но ничего никуда не переношу, имею для этого специальный alias:
Я с rebase работаю всегда в одном из двух режимов: histedit — меняю историю, но ничего никуда не переношу, имею для этого специальный alias:
ri = !sh -c 'git rebase --interactive $(git merge-base --is-ancestor ${1:-master} ${2:-HEAD} && git rev-parse ${1:-master} || git merge-base ${1:-master} ${2:-HEAD})' -
; или только перебазирование без каких‐либо изменений истории. Первое используется чаще, особенно если соглашения, принятые в проекте, не требуют обязательный rebase на master. Именно histedit используется, чтобы не терять контекста, в котором были сделаны изменения.+2
Не очень понятная формулировка. В прицнипе, это можно делать в общем репозитории в исключительных случаях.
Например, если это будет делаться в ветке, которую ведёте только вы и это не затронет коммиты до момента ответвления. Правда, в данном случае надо не забывать пушить обновления только в эту ветку (git push -f origin your_branch), так как git может быть настроен на пуш всех веток, если не указано иного и вы перезапишете изменения коллег во всех остальных ветках.
Например, если это будет делаться в ветке, которую ведёте только вы и это не затронет коммиты до момента ответвления. Правда, в данном случае надо не забывать пушить обновления только в эту ветку (git push -f origin your_branch), так как git может быть настроен на пуш всех веток, если не указано иного и вы перезапишете изменения коллег во всех остальных ветках.
0
Добавлю от себя: всегда делайте squash перед слиянием ветки с master — это позволит избежать мусора в мастере. Как мы делаем у себя на проекте?
PS: И всегда делайте интерактивный rebase. No exceptions
- Разработчик создает pull-request
- После получения достаточного количества голосов «за» разработчик делает git rebase -i HEAD~n, где n — это количество коммитов, которые он сделал в данной ветке (можно сказать, что это количество коммитов, на которое его ветка опережает master)
- Первый коммит отмечается pick, остальные — squash
- Все сообщения коммитов удаляются, первому выставляется подробное описание, что за фича, что сделал, что исправил
- git push -f
- merge
- ...
- PROFIT!
В результате вместо такого
Получаем что-то такое
PS: И всегда делайте интерактивный rebase. No exceptions
-1
Вопрос на засыпку. Чем принципиально отличаются unstaged и untracked? :)
0
untracked — ни разу не был добавлен в git. git о таком файле ничего не знает, у него нет никакой истории изменений. Это, например, могут быть какие-либо автоматически сгенерированные файлы, логи и т.п.
unstaged — файл уже добавлялся в git, сейчас он изменен, но не добавлен в будущий commit. Например, вы поменяли 5 файлов, но хотите сейчас закоммитить только 3, а оставшиеся 2 добавить в следующий commit. Вот те 2 и будут unstaged.
unstaged — файл уже добавлялся в git, сейчас он изменен, но не добавлен в будущий commit. Например, вы поменяли 5 файлов, но хотите сейчас закоммитить только 3, а оставшиеся 2 добавить в следующий commit. Вот те 2 и будут unstaged.
0
Еще полезный совет:
Если вы используете русскоязычные или любые другие не англоязычные имена файла при работе с Гит, для Вас будет полезным использование ключа -z
Например, для просмотра новых файлов можно использовать команду
Для русскоязычного имени в этом случае будет показан результат
а вот «правильная» команда
Если вы используете русскоязычные или любые другие не англоязычные имена файла при работе с Гит, для Вас будет полезным использование ключа -z
Например, для просмотра новых файлов можно использовать команду
git status --porcelain
Для русскоязычного имени в этом случае будет показан результат
?? "\320\234\320\276\320\264\321\203\320\273\321\214.txt"
а вот «правильная» команда
git status --porcelain -zпокажет намного более юзабельный вариант
?? Модуль.txt
+3
Новый вариант совершенно не юзабельный, если изменения в нескольких файлах: например, вместо
A "\302\253\302\273"
?? .git /
?? a.img
?? ab/
?? abc.c
?? foo/
показываетсяA «»?? .git /?? a.img?? ab/?? abc.c?? foo/%
(%
— это от zsh, указывает на то, что вывод предыдущей команды не был завершён новой строкой). Может, ваш терминал воспринимает нулевой байт, как новую строку, но ни один из моих нет (и не должен). Если у вас есть такие файлы, то лучше иметь что‐то вроде alias’а st = "!sh -c \"git status -z \\\"\\$@\\\" | tr '\\\\0' '\\\\n'\" -"
.0
Пожалуй, это лучшая из шпаргалок, что я читал по Git. Благодарю!
+1
SourceTree решает все проблемы
-8
Как, пожалуй, с любой технологией, к Git применимо правило 80:20. 20% знаний дают 80% профита, остальные 80% знаний дают оставшиеся 20%. Эти 20% — тоже много и нужны и, как мне кажется, статья дает именно эти 20% которых многим не хватает. Спасибо!
+2
Sign up to leave a comment.
19 советов по повседневной работе с Git