Comments 94
Консольной команды не знаю, но в Git Extensions есть функция для поиска и просмотра всех потерянных коммитов. Как правило, достаточно отсортировать их по дате — и нужные сразу же видны.
PS а для того, чтобы потерять коммит, достаточно сделать checkout ветки origin/master — при этом ветка master сразу же «прыгнет» на тот же самый коммит — а коммиты, которые были в master, но не были в origin/master — потеряются.
PS а для того, чтобы потерять коммит, достаточно сделать checkout ветки origin/master — при этом ветка master сразу же «прыгнет» на тот же самый коммит — а коммиты, которые были в master, но не были в origin/master — потеряются.
Вот только потом можно сделать git checkout обратно в мастер и они волшебным образом вернутся на место.
Нельзя. Старая ветка master исчезла.
Поясняю: речь идет о команде
Если вы спросите, кто такое делает — отвечу: git extensions именно эту команду и выполняет при попытке «просто забрать» ветвь
git checkout -B master --track origin/master
Если вы спросите, кто такое делает — отвечу: git extensions именно эту команду и выполняет при попытке «просто забрать» ветвь
origin/master
.Что значит «просто забрать»?
Согласитесь, этот пункт меню выглядит безобидно?
Тебя обманули это не гит!
Вот гит: git-scm.com/book/ru
Вот гит: git-scm.com/book/ru
Это — удобные сокращения к гиту. Работают отлично — пока понимаешь, что они на самом деле делают.
Увы, снова обманули.
Вот удобные сокращения к гиту:
Вот удобные сокращения к гиту:
alias s='git status'
alias k='gitk --all'
alias gl='git log --graph --decorate --pretty=oneline --abbrev-commit --color -n30'
alias gu='git remote -v update'
А мне кажется, обманули все-таки вас.
PS зачем вы вообще спорите? Вы что, отказываете другим людям в праве иметь любимый инструмент, отличный от вашего?
PS зачем вы вообще спорите? Вы что, отказываете другим людям в праве иметь любимый инструмент, отличный от вашего?
Как это меня обманули? Что, все-таки есть команда «просто забрать»?
git "просто забери" origin/master
Есть хак для «просто забери»: прописываете в настройках удалённого репозитория, что хотите всё забирать себе и прописываете alias
Последняя строка для того, чтобы не push’ить по‐умолчанию что попало, вторая для того, чтобы иметь «резервную копию» всех ссылок. Вся соль в третьей: она говорит git «по‐умолчанию забирай все ветки».
Но поведение mercurial всё же более понятно и более удобно.
PS: Если вы под «просто забери» не имели ввиду «просто забери всё», то дело решается либо так же (но с заменой звёздочек на имена веток), либо явным
PPS: Сразу говорю, что
fu = pull --ff-only upstream
:[remote "upstream"]
fetch = +refs/heads/*:refs/remotes/upstream/*
fetch = refs/heads/*:refs/heads/*
url = git://github.com/user/repo
pushurl = ssh://git@github.com/user/repo
push = refs/heads/develop
Последняя строка для того, чтобы не push’ить по‐умолчанию что попало, вторая для того, чтобы иметь «резервную копию» всех ссылок. Вся соль в третьей: она говорит git «по‐умолчанию забирай все ветки».
Но поведение mercurial всё же более понятно и более удобно.
PS: Если вы под «просто забери» не имели ввиду «просто забери всё», то дело решается либо так же (но с заменой звёздочек на имена веток), либо явным
git fetch origin master:master
или git pull --ff-only origin master
.PPS: Сразу говорю, что
git fu
с моим alias’ом и моим workflow будет постоянно считать, что провалился. Просто git fetch
будет проваливаться с сообщением, что не может делать fetch в текущую ветку, поэтому используется «pull в значении fetch, если текущей ветки нет в upstream, и pull в значении „сделай всё и подвинь текущую ветку“, если она есть». Но при этом после fetch будет проваливаться merge, т.к. он не знает, с чем сливать (что меня устраивает, т.к. я хотел сделать только fetch).Из-за этих клиентов одни проблемы
git reflog
бывает полезен в таких случаяхНе знал про него. я так понимаю, что он выводит тоже самое что и содержимое logs/refs/heads/branch?
А насколько нормально такие вещи, как потеря коммитов?
А насколько нормально такие вещи, как потеря коммитов?
Да, это более «user-friendly» интерфейс.
Потеря коммитов в моей практике не встречалась, а вот повреждение репы — это очень печально. Это когда содержимое не соответствует хешу и git fsck говорит «бида-бида». Это почти нельзя восстановить без бекапа.
Потеря коммитов в моей практике не встречалась, а вот повреждение репы — это очень печально. Это когда содержимое не соответствует хешу и git fsck говорит «бида-бида». Это почти нельзя восстановить без бекапа.
Есть, так сказать, «официальный» гайд по починке от самого Линуса (если кратко, в лучшем случае всё сводится к угадыванию содержимого файла дающего требуемый sha1).
В догонку к хорошим практикам. Всягда, перед тем как вообще делать коммит, а уж тем более push, нужно всегда выполнить:
git fetch origin
git status
Каждый кто серьезно пользуется гитом просто обязан это делать.
git fetch origin
git status
Каждый кто серьезно пользуется гитом просто обязан это делать.
4 часа работы потерял из-за этого бага, при выполнении pull и rebase у меня оказался заблокирован на запись один файл, git при rebase не смог его ни модифицировать ни удалить, выдал ошибку и удалил мой последний коммит со всеми изменениями. Работал через SmartGit, но он вызывает консольный git при этом.
В дальнейшем эта ситуация повторялась, с менее плачевным результатам и тоже один файл у меня был заблокирован на запись извне при попытке сделать rebase.
Ну тут мало чего сделать можно: git совершенно не рассчитан на такие чудеса, как заблокированный файл, который нельзя удалить или, там, прочитать. В Linux'е невозможность удалить файл при наличии прав обозначает, что произошла какая-то катастрофа (скажем файловая система рассыпалась или баг в ядре случился) и его обработка в git'е под это заточена.
Вполне себе кросс-платформенный. Везде где нормально поддерживается POSIX он работает отлично. Ну а если Microsoft решил смухлевать и добавить ровно столько поддержки, чтобы пропихнуть через правительственные контракты, но не столько, чтобы программы можно было реально использовать — то кто ж вам виноват? Не перекладывайте проблемы с больной головы на здоровую.
Да ну? Делаете
* root всё же может удалить, если воспользуется
chattr +i filename
или chattr +a filename
от root’а и получаете неудаляемый (даже самим root’ом*) файл при наличии прав на него. Также можно при желании настроить AppArmor/SElinux, чтобы git не мог что‐то удалить (но при этом права, в т.ч. на запись будут). Не знаю, правда, что вернёт stat
в последнем случае. Но в обоих случаях бага в ядре и рассыпавшейся файловой системы нет, а невозможность удалить файл есть.* root всё же может удалить, если воспользуется
chattr
(а также прямым редактированием блочного устройства, монтированием файловой системы с использованием собственного драйвера, игнорирующего атрибуты, или любым другим из 100500 грязных хаков, недоступных для обычного пользователя).ДелаетеВы сами-то поняли что сказали? Как вы можете говорить, что у вас есть права доступа к файлу, если вы их сами же и отобрали?chattr +i filename
илиchattr +a filename
от root’а и получаете неудаляемый (даже самим root’ом*) файл при наличии прав на него.
Да, в Linux'е есть больше одного способа отнять права доступа к файлу. Но это ничего не меняет по сути: либо права у вас есть и файл можно удалить, либо их нет — и тогда вы ССЗБ если сделали так, что к части исходников у вас доступ есть, а к части — нет.
Вы сами-то поняли что сказали? Как вы можете говорить, что у вас есть права доступа к файлу, если вы их сами же и отобрали?Права на запись и атрибуты файла — это разные сущности. Этим действием я ни у кого не отбираю права, я оставляю указание драйверу файловой системы, что ему надо делать с этим файлом. Поэтому root спокойно игнорирует отсутствие у него прав на запись, но не игнорирует атрибуты. Правда, несмотря на различный смысл, проверяется всё (атрибуты и права) практически в одном месте, по крайней мере в ядре linux.
А можно уточнить какой версией Git вы пользуетесь?
Интересно узнать это у всех версий такой глюк или допустим в 2.1.+ исправили.
Интересно узнать это у всех версий такой глюк или допустим в 2.1.+ исправили.
Мы используем git flow и ребейзим feature-ветки на develop постоянно. И только их пушаем.
git pull — злое злостное зло.
Лучше работать в тематических ветках. Git тем и хорош, что ветки в нём — не то, что trunk в svn'е.
ps: Повторяющиеся конфликты решает rerere.
git pull — злое злостное зло.
Лучше работать в тематических ветках. Git тем и хорош, что ветки в нём — не то, что trunk в svn'е.
ps: Повторяющиеся конфликты решает rerere.
git pull — злое злостное зло
Не согласен с вами. Git был придуман для максимально удобного и правильного merge, без какой-либо магии и костылей. Поэтому не нужно бояться git pull. В конце концов, всегда можно все отменить и откатиться назад.
Насчет тематических веток и Git Flow — штука интересная, но как по мне, Git Flow — это просто здравый смысл в использовании Git-веток. Так что зная базовые принципы веток Git и имея здравый смысл, вполне можно обойтись без Git Flow.
Так вы сделали pull & push или rebase?
Кто хочет сохранить прямую историю коммитов делает git pull --rebase && git push.
rebase в свою очередь видимо что-то потерял, из-за чего автору пришлось искать ответ на довольно непростой с ходу вопрос.
rebase в свою очередь видимо что-то потерял, из-за чего автору пришлось искать ответ на довольно непростой с ходу вопрос.
Я пользуюсь SmartGit там под действием pull подразумевается сразу же и rebase или merge, если не удается rebase.
git rebase
— потенциальная проблема. Например, некоторые проблемы rebase описаны в книге «Pro Git» — "The Perils of Rebasing". Моё мнение — лучше делать merge, чем rebase.И иметь отвратительную историю, где непонятный комок веток? Нет, спасибо.
А уж не ребейзить пушнутые комиты — это очевидно. Ребейз только тематических веток д.б., и точно не develop/master.
А уж не ребейзить пушнутые комиты — это очевидно. Ребейз только тематических веток д.б., и точно не develop/master.
Не буду спорить, все очевидно. Но это очевидно для вас — человека, который знает разницу. А многие, я полагаю, просто делают rebase, не думая о последствиях. Отсюда и проблемы, вроде описанной в данной статье.
Что же насчет непонятных коммитов в истории — во-первых, а что в них непонятного? Они же помечены, как merge commit, и в них есть полезная инфа. Во-вторых, GitHub / Bitbucket специально «приглушают» их в истории коммитов, так что у меня они не вызывают там дискомфорта.
Что же насчет непонятных коммитов в истории — во-первых, а что в них непонятного? Они же помечены, как merge commit, и в них есть полезная инфа. Во-вторых, GitHub / Bitbucket специально «приглушают» их в истории коммитов, так что у меня они не вызывают там дискомфорта.
Понятно: начало ветки, коммит1, коммит2, коммит3, merge blabla
Не понятно: начало ветки в далёком июле, коммит1,… over100500 коммитов..., merge from develop, коммит2, over100500 коммитов..., коммит3, merge blabla
Когда все коммиты аккуратно сложены один над другим, сразу видно, что делал человек, почему он это делал и вообще за что ему зарплату платят. Когда коммиты раскиданы, как носки по комнате, в коде мясо с фаршем и вообще всё тлен, то…
Короче я — сторонник секты аккуратности и знаю, как работает мой инструмент. И совет даю всем — пойми, что ты делаешь и думай о других, кто будет читать твой код. Это заповедь, скрижаль.
Не понятно: начало ветки в далёком июле, коммит1,… over100500 коммитов..., merge from develop, коммит2, over100500 коммитов..., коммит3, merge blabla
Когда все коммиты аккуратно сложены один над другим, сразу видно, что делал человек, почему он это делал и вообще за что ему зарплату платят. Когда коммиты раскиданы, как носки по комнате, в коде мясо с фаршем и вообще всё тлен, то…
Короче я — сторонник секты аккуратности и знаю, как работает мой инструмент. И совет даю всем — пойми, что ты делаешь и думай о других, кто будет читать твой код. Это заповедь, скрижаль.
На мой взгляд ситуация относится уже к advanced usage, нежели daily workflow. Беглый поиск в рунете по этой теме вообще ничего не дал.
Пассаж про Рунет относится к тому, что Хабр русскоязычный ресурс и я не вижу ничего плохо, что описание и решение подобной ситуации теперь есть и на русском.
Что же касательно инструмента, то в ежедневной работе я использую порядка десятка различных технологий и инструментов и знать их все от и до невозможно, да и нет необходимости. Если вы детально разбираетесь в схеме работы Гита это прекрасно, но для множества разработчиков это является нештатной ситуацией с не очень понятными причинами и условиям выхода.
Я разрулил конфликты. закончил rebase и был уверен что пуш ушел, потому что в исходящих комитах было пусто. Я это проделывал сотню раз. О том, что rebase может перескочить комит я узнал только спустя лет 5 пользования Гитом.
Что же касательно инструмента, то в ежедневной работе я использую порядка десятка различных технологий и инструментов и знать их все от и до невозможно, да и нет необходимости. Если вы детально разбираетесь в схеме работы Гита это прекрасно, но для множества разработчиков это является нештатной ситуацией с не очень понятными причинами и условиям выхода.
Я разрулил конфликты. закончил rebase и был уверен что пуш ушел, потому что в исходящих комитах было пусто. Я это проделывал сотню раз. О том, что rebase может перескочить комит я узнал только спустя лет 5 пользования Гитом.
Ну какой advanced usage, про это даже есть раздел в самой обычной документации, который так и называется, "Обслуживание и восстановление данных".
Вы только не забывайте, что когда-нибудь гит сделает GC, и такие ваши коммиты, которых нету ни в одном бранче, уничтожатся навсегда. Так что не особо часто надейтесь на эту фичу.
Вообще говоря, те коммиты, которые еще можно найти через reflog, не удаляются при стандартном git gc
Ну и общее правило по поиску потеряных вещей — чем раньше спохватишься, тем вероятнее найти — тут тоже работает.
Ну и общее правило по поиску потеряных вещей — чем раньше спохватишься, тем вероятнее найти — тут тоже работает.
Автоматический GC прекрасно выключается с помощью
git config --global gc.auto 0
. И под сборку мусора коммиты попадут только через 30 дней, если не выкручивать никаких ручек вроде gc.reflogExpireUnreachable
.Еще одна статья о том, что git rebase — зло. Почему вы все еще его используете?
Я rebase использую буквально каждый день и вижу только добро.
А лопухи, которые не понимают что делают, пускай пеняют на себя.
А лопухи, которые не понимают что делают, пускай пеняют на себя.
Можно поинтересоваться — зачем вы rebase используете каждый день?
1. нравится мне линейная история: если фикс мелкий (т.е. не фича-бранча), то перед пушем делаю git pull --rebase, чтобы избежать мерж коммита.
2. когда долго работаю в своей ветке то ребэйс делаю чтобы получить свежие изменения (если что-то критичное починили)
3. если я быстро заметил баг в предпоследнем коммите (и еще не пушал), то коммичу фикс, делаю git rebase -i HEAD~3 и объединяю с тем коммитом в котором я баг добавил. Это чтобы не дефрагментировать историю тайпо-фиксами.
2. когда долго работаю в своей ветке то ребэйс делаю чтобы получить свежие изменения (если что-то критичное починили)
3. если я быстро заметил баг в предпоследнем коммите (и еще не пушал), то коммичу фикс, делаю git rebase -i HEAD~3 и объединяю с тем коммитом в котором я баг добавил. Это чтобы не дефрагментировать историю тайпо-фиксами.
Вообще конечно большой плюс гита в том, что потерять коммит практически нереально. Конечно, если не сделать агрессивный gc сразу после. Коммит всегда будет где-то, и через reflog ли, или просто поиском объекта, но этот коммит можно найти и использовать.
Потому коммитить надо часто и не стесняться мерджить и ребейзить.
Потому коммитить надо часто и не стесняться мерджить и ребейзить.
Однажды я сильно не выспавшись занялся любимым делом, и по запарке случилось git stash, что-то ещё и наконец git stash clear (коммита не было). Доставал как-то так:
Показал мне кучу хэшей, но за искомым хэшем вывел строку, заданную в последнем grep. Так я взял нужный хэш, по которому успешно всё восстановил, закоммитил и запушил.
С тех пор стал стараться делать коммиты меньше и чаще.
git fsck --unreachable | awk '{print $3}' | while read hash; do echo $hash; git show $hash | grep 'тут кусок - разница'; done
Показал мне кучу хэшей, но за искомым хэшем вывел строку, заданную в последнем grep. Так я взял нужный хэш, по которому успешно всё восстановил, закоммитил и запушил.
С тех пор стал стараться делать коммиты меньше и чаще.
Рекомендую всегда делать
rebase -i
, чтобы убедиться, что перенесены будут именно ожидаемые коммиты.Вот только что видел проблему в команде именно с rebase -i.
Верхний коммит — изменение и одновременно нужный merge. git rebase -i показывает совершенно другие коммиты — видно все свои изменения выкинуты.
С широко раскрытыми глазами редактор закрывается без единого изменения (в попытке убрать этот кошмар), и git спокойно (и радостно для наблюдающих) так и делает всю ветку.
Потом восстанавливали примерно как тут написано.
Верхний коммит — изменение и одновременно нужный merge. git rebase -i показывает совершенно другие коммиты — видно все свои изменения выкинуты.
С широко раскрытыми глазами редактор закрывается без единого изменения (в попытке убрать этот кошмар), и git спокойно (и радостно для наблюдающих) так и делает всю ветку.
Потом восстанавливали примерно как тут написано.
> редактор закрывается без единого изменения (в попытке убрать этот кошмар)
А откуда взялась идея, что отсутствие изменений == отмена rebase? :) Это вообще-то то же самое, что и просто rebase, без -i
Для отмены операции нужно текстовый буфер в редакторе очистить и сохранить, тогда git обидится на отсутствие коммитов и ничего делать не будет.
А откуда взялась идея, что отсутствие изменений == отмена rebase? :) Это вообще-то то же самое, что и просто rebase, без -i
Для отмены операции нужно текстовый буфер в редакторе очистить и сохранить, тогда git обидится на отсутствие коммитов и ничего делать не будет.
P.S. rebase своеобразно сочетается с merge commit — в обычном логе последний показывается как один коммит, но в списке rebase -i будут указан полный список коммитов второго родителя.
Если вы используете Vim, то можно ничего не удалять, а написать
:cq<CR>
: тогда git будет считать, что он не смог запустить редактор и отменит rebase (:cquit
заставляет Vim выйти с кодом возврата 1).Прочитав статью я порадовался, что мой линукс (а соответственно и гит на нем) лежит на виртуалке в VirtualBox, а разработку веду на phpStorm (с синхронизацией по sftp) на винде в папке под дропбоксом.
И чему тут радоваться?
Потерять код невозможно в принципе. Если что-то случится с линуксом или гитом, всегда есть актуальная копия в винде, если что-то потеряно в винде, всегда можно восстановиться из дропбокса.
При грамонтном использовании гит — потерять код тоже невозможно.
Как выше писали, автор сам виноват, что появилась такая проблема.
И у вас могла быть такая же проблема.
И дробокс тут не сильно бы помог, ибо лазать по истории в десятках файлах и выуживать оттуда данные сложнее, чем из гит-а.
Как выше писали, автор сам виноват, что появилась такая проблема.
И у вас могла быть такая же проблема.
И дробокс тут не сильно бы помог, ибо лазать по истории в десятках файлах и выуживать оттуда данные сложнее, чем из гит-а.
>> При грамонтном использовании гит — потерять код тоже невозможно.
Ну сломаться не только гит может, а еще 100500 разных вещей, вплоть до харда.
>> И у вас могла быть такая же проблема.
Ну была бы, и что. Удалил бы локальный репозиторий, заново склонировал удаленный репозиторий и синхронизировал с папкой на винде. Там-то код не потерялся.
>> И дробокс тут не сильно бы помог, ибо лазать по истории в десятках файлах и выуживать оттуда данные сложнее, чем из гит-а.
Ну это еще спорный вопрос. И все же они там есть, и это главное.
Ну сломаться не только гит может, а еще 100500 разных вещей, вплоть до харда.
>> И у вас могла быть такая же проблема.
Ну была бы, и что. Удалил бы локальный репозиторий, заново склонировал удаленный репозиторий и синхронизировал с папкой на винде. Там-то код не потерялся.
>> И дробокс тут не сильно бы помог, ибо лазать по истории в десятках файлах и выуживать оттуда данные сложнее, чем из гит-а.
Ну это еще спорный вопрос. И все же они там есть, и это главное.
Я взял за практику делать git stash перед git pull.
А когда git pull завершился, я делаю git stash apply.
Если тут возникают конфликты, исправляю.
В итоге у меня мой коммит единственный и идёт всегда после мерджа с master'ом.
А когда git pull завершился, я делаю git stash apply.
Если тут возникают конфликты, исправляю.
В итоге у меня мой коммит единственный и идёт всегда после мерджа с master'ом.
угу, давно сделал себе алиас git up:
(впрочем это для тех кто знает как резолвить конфликты)
up = !(git add . && git stash && git pull --rebase >&2) | grep -v 'No local changes to save' && git stash pop
(впрочем это для тех кто знает как резолвить конфликты)
Для этого есть
git rebase --autostash
и соответствующая настройка rebase.autostash
. Я, правда, не в курсе, когда это появилось. У меня версия 1.8.5.5.SmartGit и делает stash перед каждым потенциально критичным действием. Проблема была в том, что stash работает только с незакоммиченными файлами. У меня же уже был сделан коммит, который git успешно откатил без следа во время неудачной попытки сделать ребейс.
Вот из-за такой х__ни я держу исходники всех проектов в Dropbox с проплаченным Extended Version History (бывший PackRat).
Это позволяет откатиться на любую версию любого файла.
Это позволяет откатиться на любую версию любого файла.
И, кстати, вот как себя ведёт mercurial при rebase/histedit/любая другая команда, удаляющая изменения: он вам явно прямо в консоли пишет, где сохранил резервную копию старых коммиттов и не удаляет их автоматически (git иногда сам запускает
git gc
, после него вы бы ничего не нашли). Авторы git же считают, что про git reflog
надо было читать, до того, как вы написали git rebase
, а запуск git gc --auto
после rebase
— это вообще свинство.В чем же свинство? git gc --auto не чистит коммиты, доступные из рефлога (при стандартных настройках)
Не знал. Я привык в reflog видеть сотни коммитов, поэтому полагал, что без чистки коммитов из reflog’а
git gc
не слишком полезен.Если уж точно, то он чистит сам reflog от старых записей (см. настройки
А потом и удаляет старые объекты, на которые нет ссылок (см.
gc.reflogExpire
[90 дней по умолчанию] и gc.reflogExpireUnreachable
[30 дней по умолчанию]).А потом и удаляет старые объекты, на которые нет ссылок (см.
gc.pruneExpire
[2 недели по умолчанию]).> То ли баг в Гите, то ли мои неправильные действия, которые я в запарке не заметил.
за последние 5 лет я ни разу не терял коммиты в git. ЧЯДНТ?
за последние 5 лет я ни разу не терял коммиты в git. ЧЯДНТ?
Sign up to leave a comment.
Странный глюк Git, чуть не стоивший 10 часов работы