LINUX.ORG.RU

Вопрос про Git. Он, правда, позволяет так легко потерять данные?

 , ,


9

7

Я тут на пробу пытаюсь парочку репозиториев перевести с привычного Mercurial на инопланетной логики Git в надежде разобраться с последним. И, ладно бы только логика работы, к ней можно привыкнуть. Но я уже несколько раз терял свои наработки с Git, чего с Mercurial не было никогда за всю историю. Пару раз терял так, что концов не найти, но вот сейчас всю цепочку отследить попробовать можно. Посему и прошу комментариев народа опытного.

Суть такая. Есть поднятый весной и так и не развитый репозиторий https://github.com/Balancer/bors-3rd-bootstrap3

Сейчас решил перекинуть туда код (со всей историей) по работе с bootstrap из ядра фреймворка, которое лежит в Mercurial на Bitbucket. Благо, есть такая прекрасная штука, как hg-git. Перенос файлов со всеми изменениями из репы в репу под Git возможен, но выглядит это чудовищно. Посему, решил вынести сперва отдельный маленький локальный репозиторий Mercurial с этими файлами, к нему подтянуть дерево Git, смержить средствами Mercurial и запушить в репу Git.

Сделать это было чуть дольше, чем написать предыдущий абзац, но работа небольшая, всё было проведено легко и непринуждённо. На GitHub'е появился объединённый модифицированный код. Всё прекрасно.

Дальше начинаются вещи непонятные. Я работал также с другой машины, там были мелкие правки (типа composer.json в корне). Решил всё объединить. Точную последовательность не помню, но, скорее всего обычные git pull && git push на другой машине.

После этого, чтобы точно убедиться, что изменения синхронизированы, провёл после git fetch (там --bare) на первой машине git push... И увидел странное:

To git@github.com:Balancer/bors-3rd-bootstrap3.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:Balancer/bors-3rd-bootstrap3.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Ну, что, Google в помощь, и первый же совет, который нахожу — воспользоваться ключиком «-f». Не вопрос. У нас же DVCS, даже если что-то не так, всегда можно откатить и т.п. Логика, привитая Mercurial'ом, ага...

Ничтоже сумняшеся, обновляю composer на другой машине и... вижу, что всех изменений, которые я переносил в эту репу нет. Удивляюсь. Вызываю git log --graph (вот почему в git по дефолту все команды такие длинные и несуразные?) — чистота. Всё в превозданном виде семимесячной давности, без переноса нового кода с основного репо.

Лезу на GitHub — и вот тут становится совсем интересно. Те изменения, что я накатывал и которые там были, теперь там отсутствуют o_O

Так вот, вопрос. Это я их не вижу, или это в Git так легко, одним движением руки можно убить безвозвратно серию коммитов с историей? o_O Если первое — то вопрос, как вернуть эти изменения. В основной репе я их уже успел прибить, но всегда можно откатить и повторить перенос. Придётся повозиться, но задача не столь сложная. Но хочется разобраться. Ибо если в Git так легко потерять изменения, то как с ним вообще люди живут?

★★★★★

Последнее исправление: CYB3R (всего исправлений: 1)
Ответ на: комментарий от Deleted

И кстати, ключи и пароли, закоммиченые в локальный репозиторий ещё не скомпрометированы. Их можно просто удалить из истории.

Зачем менять историю, если можно просто не коммитить локальные изменения на публичный сервер, просто склонировав локальную версию конкретной ревизии (до ошибочного добавления ключей) и закоммитить уже её?

KRoN73 ★★★★★
() автор топика

Честно говоря, я уже не понимаю о чём спор. Я на работе использую git. Если я сделаю push --force, то сервер (gerrit) просто пошлёт меня подальше, так как у меня нет прав. И всё.

Если github не позволяет настроить так же - то это исключтельно проблемы гитхаба, а не гита.

Deleted
()
Ответ на: комментарий от KRoN73

Зачем менять историю, если можно просто не коммитить локальные изменения на публичный сервер, просто склонировав локальную версию конкретной ревизии (до ошибочного добавления ключей) и закоммитить уже её?

затем, что когда репозиторий размером 25 гигов — это боль. (поэтому я и в hg просто использую amend, strip и т.п.)

waker ★★★★★
()
Последнее исправление: waker (всего исправлений: 1)
Ответ на: комментарий от waker

Он ничего не удаляет. При таком подходе ветки продолжают исполнять своё назначение — отображать, какие коммиты частью каких более крупных сущностей являются.

vurdalak ★★★★★
()
Ответ на: комментарий от KRoN73

Зачем менять историю, если можно просто не коммитить локальные изменения на публичный сервер, просто склонировав локальную версию конкретной ревизии (до ошибочного добавления ключей) и закоммитить уже её?

А если после ключей ты уже навалил десяток-другой коммитов?

Но да, тут кроме переписывания локальной истории есть ещё один способ: создать ещё одну ветку, и перенести в неё только правильные коммиты. А старую ветку грохнуть.

Deleted
()
Ответ на: комментарий от vurdalak

Я не очень понимаю, зачем это пушить именно в виде ветки. Если она сразу после пуша удаляется, какой в ней смысл? Почему нельзя запушиьть эти два коммита сразу в мастер?

И как я это локально должен разруливать, если я одновременно работаю над несколькими немаленькими фиксами?

Deleted
()
Ответ на: комментарий от vurdalak

И пушу я не «в виде ветки», а просто как серию коммитов, которые отличают мою локальную ветку от удалённой «родительской». То есть после пеша в центральном репозитории не будет никаких следов, что у меня эти коммиты были в отдельной ветке.

Deleted
()
Ответ на: комментарий от Deleted

Но да, тут кроме переписывания локальной истории есть ещё один способ: создать ещё одну ветку, и перенести в неё только правильные коммиты. А старую ветку грохнуть.

о, а расскажи как? я бы с радостью имел такую фичу в hg. всмысле, как грохать ветки. про graft я и так знаю.

waker ★★★★★
()
Ответ на: комментарий от Deleted

То есть ветка чисто локальная? ИМХО, тогда это должна быть не ветка (которая может быть удалённой и вечной), а какая-то отдельная сущность с другим названием.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

Сколько у тебя рук и глаз, наркоман?

Две руки и два глаза!

Я не могу просто взять и запушить код сразу после того, как я его напишу. Нужно ещё как минимум чтобы ревьюверы его посмотрели и сказали своё «годно». В некоторых случаях ещё нужно отправить его тестерам, чтобы они его потестили на своих юзкейзах. На всё это может уйти неделя и даже не одна. Предлагаешь мне всё это время ничего не делать?

Deleted
()
Ответ на: комментарий от Deleted

Честно говоря, я уже не понимаю о чём спор

Так с самого начала почти о концепции DVCS в отношении неизменности истории.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

И как я это локально должен разруливать, если я одновременно работаю над несколькими немаленькими фиксами?

не слушай его. в hg тоже все плодят тыщи feature-branches. потом мержат, и закрывают (--close-branch). если кто забывает закрывать - приходит мантайнер репозитория, и бьет по рукам логарифмической линейкой. если не закрывать — то фронтенд захлебывается, когда пытается вебсайтик отобразить.

waker ★★★★★
()
Ответ на: комментарий от waker

о, а расскажи как? я бы с радостью имел такую фичу в hg. всмысле, как грохать ветки. про graft я и так знаю.

Я про git говорю. Коммиты перенести можно просто cherry-pick'ом, а старый бранч удалить с помощью branch -D.

Deleted
()
Ответ на: комментарий от Deleted

Предлагаешь мне всё это время ничего не делать?

shelve, потом работаешь над своим кодом. Когда пришло время запушить, шелвишь текущий, возвращаешь тот и пушишь.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

То есть ветка чисто локальная? ИМХО, тогда это должна быть не ветка (которая может быть удалённой и вечной), а какая-то отдельная сущность с другим названием.

Тогда эта сущность будет отличаться от «ветки» только названием =).

Deleted
()
Ответ на: комментарий от Deleted

А если после ключей ты уже навалил десяток-другой коммитов?

Опять очень редкая ситуация. Навалить коммитов, зевнуть ключ, заметить это где-то в дебрях коммитов до пуша... — это реально редкое стечение обстоятельств. Обычно ключ замечаешь либо в последних коммитах, либо уже после публикации. В таком редком случае можно применить и _защищённый_ механизм модификации истории.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Нет, не только. Можно запретить эту сущность куда-либо пушить. И автоматически удалять, когда все коммиты из неё будут запушены.

vurdalak ★★★★★
()
Ответ на: комментарий от Deleted

Я про git говорю. Коммиты перенести можно просто cherry-pick'ом, а старый бранч удалить с помощью branch -D.

да в git я и сам прекрасно знаю, думал ты это про hg писал.

waker ★★★★★
()
Ответ на: комментарий от waker

если не закрывать — то фронтенд захлебывается, когда пытается вебсайтик отобразить.

Кстати, может мне здесь подскажут. Как на гитхабе смотреть список коммитов по всем веткам как на битбакете? Т.е. есть некий проект. Я периодически захожу и смотрю, насколько активно он разрабатывается. Однажды захожу и вижу, что коммитов не было уже месяц. А всё потому, что они сейчас работают над другой веткой, а гитхаб по умолчанию показывает только мастер. И приходится руками каждую ветку по очереди смотреть.

vurdalak ★★★★★
()
Ответ на: комментарий от KRoN73

В таком редком случае можно применить и _защищённый_ механизм модификации истории.

ога, расскажи нам, как этот механизм называется, и где его взять, в hg.

waker ★★★★★
()
Ответ на: комментарий от vurdalak

shelve, потом работаешь над своим кодом. Когда пришло время запушить, шелвишь текущий, возвращаешь тот и пушишь.

Хм... Выглядит как git stash. Для моих юзкейзов не юзабельно.

Deleted
()
Ответ на: комментарий от Deleted

Выглядит как git stash.

Он самый.

Для моих юзкейзов не юзабельно.

Для каких именно? Для того что ты описал выше юзабельно, я сам так делаю (только shelve средствами IDE а не VCS, потому что мышевозить люблю).

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

Можно запретить эту сущность куда-либо пушить.

Эм... И какой тогда в ней будет смысл? Я пушу это ветку, просто пушу в удалённую ветку с другим названием.

И автоматически удалять, когда все коммиты из неё будут запушены.

Не всегда нужно удалять её сразу. Кстати, git branch -d не даёт просто так удалить ветку, изменения из которой никуда не запушены.

Deleted
()
Ответ на: комментарий от Deleted

Я пушу это ветку, просто пушу в удалённую ветку с другим названием.

Ты не пушишь ветку, ты пушишь набор коммитов. Локальная ветка на удалённом репозитории не появляется, в отличие от «настоящей» ветки.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

Я периодически захожу и смотрю, насколько активно он разрабатывается.

там есть вкладка pulse справа. выдает статистику по коммитам, мержам и т.п.

без гитхаба: git log --branches.

waker ★★★★★
()
Ответ на: комментарий от vurdalak

Для каких именно? Для того что ты описал выше юзабельно, я сам так делаю (только shelve средствами IDE а не VCS, потому что мышевозить люблю).

Возможно мы друг друга не понимаем. У меня несколько веток-фиксов. В каждой ветке несколько коммитов, у каждого коммита может быть длинное сообщение с описанием что, зачем и как я изменил. stash так не может, он просто где-то сохраняет текущие изменения и откатывает их.

Deleted
()
Ответ на: комментарий от Deleted

Ага, теперь понял. Мой вариант был без коммитов.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

Ты не пушишь ветку, ты пушишь набор коммитов. Локальная ветка на удалённом репозитории не появляется, в отличие от «настоящей» ветки.

И в чём принципиальная разница? Я могу запушить в ветку с таким же названием, а могу в другую ветку.

Deleted
()
Ответ на: комментарий от waker

там есть вкладка pulse справа. выдает статистику по коммитам, мержам и т.п.

Это немного не то. Он не показывает сами коммиты, только график. Я же хочу увидеть такое: X сделал коммит Y в мастер, потом X сделал коммит Z в ветку W, затем A сделал коммит в ветку W и так далее. Т.е. «общую историю по всем веткам».

vurdalak ★★★★★
()
Ответ на: комментарий от Deleted

В том что локальная ветка никуда не уходит. Она хранится только локально и строго говоря вообще частью истории не является.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

В том что локальная ветка никуда не уходит. Она хранится только локально и строго говоря вообще частью истории не является.

Это не принципиальная разница. В гите, как по идее и в любой другой DVCS, все репозитории равноправны. Удалённая ветка в «центральном» репозитории такая же локальная для него самого, как и моя локальная ветка локальна для меня. Однажды я могу захотеть дать доступ к своему локальному репозиторию кому-то ещё, чтобы он смог с меня склонировать мою локальную ветку =).

Deleted
()
Ответ на: комментарий от Deleted

Я имею в виду, что коммиты могут бегать между ветками как хотят. В меркуриале ветка это атрибут коммита. Нельзя просто взять и запушить коммиты в другую ветку, а локальную похерить.

vurdalak ★★★★★
()

то я их не вижу, или это в Git так легко, одним движением руки можно убить безвозвратно серию коммитов с историей?

Да. Но это если один девелопишь. Обычно можно позвонить коллеге/другу, что бы тот запушил свою ревизию. А вообще, везде написано, что force-push - зло. И вначале лучше сделать pull, пофиксить конфликты(если есть), и после этого с чистой совестью push. Вообще для кого git workflow писан?!

fang90 ★★★★★
()
Последнее исправление: fang90 (всего исправлений: 1)
Ответ на: комментарий от Deleted

Хм... Выглядит как git stash. Для моих юзкейзов не юзабельно.

вообще говоря, git stash помощнее чем hg shelve :) намного. и юзкейсов поэтому у него больше. так что вполне можно оценить, какие юзкейсы у vurdalak, если ему хватает того кривого огрызка.

waker ★★★★★
()

В позапрошлый или позапозапрошлый ICFPC с помощью гита удалили улучшенный AI.

turtle_bazon ★★★★★
()
Ответ на: комментарий от KRoN73

Никакого противоречия. Пользователь Git обладает большими возможностями.

Но там где большая сила, там и большая ответственность (c).

Pinkbyte ★★★★★
()
Ответ на: комментарий от KRoN73

Именно «-f» можно, действительно, случайно ввести.

Вы прослушали лекцию о вреде прежде временных сокращений :-)

Хинт от человека, который 1 раз(всего 1 сраный раз) таки грохнул себе по пьяни /var/lib кажется: 'rm путь_к_удалению -rf'

В чём тут хитрость? А в том, что пока уточняешь путь(я тоже человек и тоже, внезапно могу отвлечься) даже если придавишь на Enter и это будет директория - ничего не произойдет.

Это и есть выстрел в ногу, когда ты этого выстрела не желаешь.

смотри хинт выше

git push origin master -f

То есть ключ вводим когда точно уверены что усё ок.

Pinkbyte ★★★★★
()
Ответ на: комментарий от vurdalak

Я удивился, когда обсуждал с человеком гит, и он сказал что создаёт по 100500 веток и после мержа их удаляет. Нафига ветки тогда нужны вообще, я так и не понял.

Я так тоже делаю, иногда это удобнее чем делать rebase, но тут есть свои тонкости. С rebase история выглядит чище

Pinkbyte ★★★★★
()
Ответ на: комментарий от Deleted

github ЕМНИП не позволяет. А вот gitolite - вполне.

Pinkbyte ★★★★★
()
Ответ на: комментарий от vurdalak

Открываешь график «Network» и смотришь всё дерево коммитов.

Осторожно: на больших репозитариях github рисует для этого графика развесистый HTTP Error 502 после того как браузер пару минут потупит. Например - на дереве исходников ядра.

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

Пичалька. Вроде фича на 5 минут, достаточно взять готовый код вывода коммитов по веткам, и убрать фильтрацию. Ан нет.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

готовый код вывода коммитов по веткам, и убрать фильтрацию.

это в hg нужна фильтрация, чтобы вывести лог 1 ветки, а в git log это дефолтное поведение.

но ты прав, фича на 5 минут - нужно просто аргумент --branches добавить.

waker ★★★★★
()
Ответ на: комментарий от waker

но ты прав, фича на 5 минут - нужно просто аргумент --branches добавить.

Я это и имел в виду под убиранием фильтрации :)

vurdalak ★★★★★
()
Ответ на: комментарий от KRoN73

Только в mercurial это делается точно также, как в git :)

Вот теперь всё понятно. Привыкнув к воркфлоу меркуриала ты, не разоравшись решил применить его для гита. Как результат, переписал tip основной ветки на гитхабе.

Вместо того, чтобы разобраться что и почему, ты придумал сферическую DVCS в вакууме, которой меркуриал якобы соответствует, а гит — нет.

После того как тебя приперли к стенке в т.ч. и вытащенными из закосяченной локальной копии коммитами, ты применил широко известный аргумент, мол заранее настроенный негибкий воркфлоу намного лучше гибкого. Увы, это аргумент всех виндузятников, поклонников .Net и прочей околокомпьютерной мерзости. Применять такую аргументацию на ЛОРе достаточно бессмысленно. Даже хорошей еды не сгенерируешь.

Справедливости ради отмечу, что в данном случае гит повёл себя неинтуитивно. Вместо того, чтобы отвязать HEAD от refs/master (или чего там) и громко об этом сообщить, гит отправил в небытие солидный кусок истории.

С другой стороны, у гита есть reflog, куда записываются предыдущие состояния рефов. Пока ссылка на коммит есть в рефлоге, сборщик мусора не будет его жрать. Рефлог гибко настраивается. Например, можно сделать так чтобы для важного подмножества веток он не истекал никогда, т.е. абсолютная защита от кривых rebase'ов, reset'ов, pull'ов и т.п.

Опять же справедливости ради, гитовский или гитхабовский ГУЙ или не поддерживают работу с рефлогом.

Но вот блогпост про использование АПИ гитхаба для восстановления репозитория, ну прям про тебя ;) http://www.objectpartners.com/2014/02/11/recovering-a-commit-from-githubs-ref...

Macil ★★★★★
()
Ответ на: комментарий от Pinkbyte

есть еще --dry-run где уместно, гит поддерживает по возможности этот режим

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.