LINUX.ORG.RU

Git: как вставить файл задним числом?

 , , , трюки


0

1

Поскольку я давно уже (после многократных холиворов на этот счёт) понял, что инопланетную логику git'а на чём-то сложнее ci/push/pull/fetch мне не постичь, но меня убедили, что его гибкость — это его сила, вот задача на такую гибкость.

Ткните пальцем, как простым средством вставить файл в репозиторий задним числом. Точнее, даже коммит, пожалуй, речь именно о фиксации изменения задним числом. Т.е. есть текущее состояние. Есть где-то старая версия файла, которая в коммитах не была зафиксирована. Как внести это старое значение файла в историю изменений?

★★★★★

Думаю тебе нужен git rebase.

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

А точнее? Я же писал, что логику git'а я не осиливаю. В приведённых командах я не вижу возможности вставить коммит «задним числом».

И, да, на всякий случай — потребуется явная игра с указателями или как они там в git'е называются. Нельзя пересоздавать весь репозиторий в новых местах и накатывать патчи. Объёмы данных — десяток гигабайт и более, миллион файлов, миллионы коммитов.

KRoN73 ★★★★★
() автор топика
Последнее исправление: KRoN73 (всего исправлений: 1)
git branch i-want-to-instert-file <point-before-where-you-want-to-instert>
git checkout i-want-to-instert-file
git add/commit -m 'inserting file'
git checkout master
git rebase i-want-to-insert-file
git push -f master # заливаем исправленную историю. кто не спрятался - я не виноват
Sectoid ★★★★★
()

никак, иначе бы не отпачковывались стабильные ветки программы Linux.

anonymous
()

что-то я условия нифига не понимаю...
у тебя есть новая версия файла в репе, но тебе надо запушить (со старой датой коммита) какаую-то старую версию файла котороая НЕ в репе?

q11q11 ★★★★★
()

Если тебе надо просто зафиксировать старую версию, то:

  1. Закоммить старую версию
  2. git revert HEAD — верни все как было
  3. git push — поделись с друзьями

Если удалённый сервер разрешает модерацию push force, то можешь даже сделать красивую историю:

  1. Коммитишь старую версию файла
  2. git rebase -i HEAD~<сколько коммитов назад нужно было вкоммитить + 1> и перемещаешь строчку со своим коммитом куда надо
  3. С вероятностью 99.9(9)% возникнут конфликты. Решаются просто:git checkout HEAD . (вот тут точно не помню, либо HEAD либо коммит *после* HEAD)
  4. git push --force
  5. Горишь в аду
KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от q11q11

у тебя есть новая версия файла в репе, но тебе надо запушить (со старой датой коммита) какаую-то старую версию файла котороая НЕ в репе?

Да.

Если более конкретно, то задача такая. Есть некая (большая) файловая текстовая структура, и стартовавшая с какого-то момента фиксация изменений в git. Периодически находятся старые версии файлов, которые были ДО запуска системы контроля версий. И хочется подсунуть их в историю так, чтобы файлы в ней вели себя, как если бы они оказались там в своё время, раньше. Т.е. чтобы можно было показать, скажем, diff между этой старой версией и текущей.

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

ну ты как-бы сам понял что с тобой сделаю те кто после этого выполнит git pull

ну кагбэ постановка ТСа это само собой разумеет.

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

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

не думаю что это вообще возможно
задача абсолютно нетривиальная в терминах любой системы контроля версий

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

задача абсолютно нетривиальная в терминах любой системы контроля версий

Ну, просто в рамках старого холивора о разном подходе к идеологии работы с историей в mercurial vs git, мне, на замечание о том, что mercurial гораздо щепетильнее отностится к истории, чем git, возражали, в духе, «зато git позволяет крутить историю как угодно, что бывает полезно и нужно». Вот возникла у меня как раз такая задача, отсюда и вопрос :)

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

Ты же работаешь с изменениями. Можешь закоммитить устаревший файл, а потом на него накатить все изменения с определенной ревизии до HEAD (то есть до того момента как ты этот файл добавил). Получится более-менее то, что тебе нужно, но история будет не очень красивая.

alozovskoy ★★★★★
()

мне git rebase --interactive нравится

MyTrooName ★★★★★
()

У меня есть журнал (школьный дневник, выдачи мат. ценностией, посещений, лабораторный, бортовой), как мне внести изменения задним числом?

Никак. Выдрать уже исписанные страницы, добавить нужное событие, переписать выдранные страницы. Но это будет уже другой журнал.

Собственно говоря, «ради этого всё и затевается». Где ты углядел инопланетную логику?

Такая же архитектура и у биткоина. С той лишь разницей, что каждый «объект» подписан, а для формирования «коммита» нужно посчитать хэш с энным количеством ноликов... Кстати, замечательная идея для гита.

Учти, что за push -f не в свой собственный бранч, отпиливают руки двуручной пилой. Очень ме-е-е-е-дленно... Ибо, более мерзкой подлянки в гите сделать просто невозможно.

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

Учти, что за push -f не в свой собственный бранч, отпиливают руки двуручной пилой. Очень ме-е-е-е-дленно...

В нормальных репах обычно вообще push -f в главные ветки выдаёт отлуп. Ибо нехер.

EXL ★★★★★
()
git rebase -i @хэш_предшествующего_заднему_числу_коммита@
В открывшемся редакторе напротив требуемого коммита меняете pick на edit
git add filename
git commit --amend
git rebase --continue

Но изменится история, это одинаково плохо/хорошо инвариантно относительно SCM.

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

возражали в духе, «зато git позволяет крутить историю как угодно, что бывает полезно и нужно»

честно, понятия не имею что имеется ввиду под «git позволяет крутить историю как угодно», но кажется это не подазумевает редактирования истории / дерева коммитов руками :):)

q11q11 ★★★★★
()

rebase до нужного места, commit фаила, а дальше гит всё что было накатит снова.

Но учитывай, чудес не бывает и hash коммитов уедут, и в remote репозиторий надо будет коммитить с --force и если кто-то этим пользовался кроме тебя, ему предстоит весёлый merge.

Так что игры с историей это дело тонкое.

Я бы так не делал.

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

У меня есть журнал (школьный дневник, выдачи мат. ценностией, посещений, лабораторный, бортовой), как мне внести изменения задним числом?

Вклеить страницу.

Никак. ... это будет уже другой журнал.
Собственно говоря, «ради этого всё и затевается».

Я прекрасно вижу это «затевается» в Mercurial. Но в Git неловким движением руки легко потерять часть истории. И когда я на это возмущался, мне на ЛОРе многократно, убедительно и с примерами писали, что именно в такой гибкости и сила Git'а. Я поверил, решив для себя, что там, где нужна более надёжная история я по-прежнему буду использовать Mercurial. А когда потребуется система с модификацией истории задним числом — обращусь к Git. Сейчас, вот, потребовалась такая система, как раз. Но фанаты Git'а, которые прошлый раз мне убедительно доказывали, что в Git так можно (и иногда нужно), пока в теме не появлялись :)

Где ты углядел инопланетную логику?

Слова про инопланетную логику касаются не вопроса надёжности истории, а вопроса логики связей коммитов и работы с ними.

Учти, что за push -f не в свой собственный бранч, отпиливают руки двуручной пилой.

Это не коллективная работа с кодом. Это собственная система, задача которой не сохранение истории неизменной, а дополнение старой истории найденными позже артефактами.

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

честно, понятия не имею что имеется ввиду под «git позволяет крутить историю как угодно»

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

но кажется это не подазумевает редактирования истории / дерева коммитов руками :):)

Главные аргументы защитников «редактирования истории» git касались в основном двух юзкесов:
— «Я когда-то по ошибке закоммитил пароль/ключ API, результат уже в дереве изменений, но ещё не ушёл в продакшн, я хочу убрать этот пароль в предыдущих коммитах»
— «Я делаю много временных мусорных коммитов, но хочу, чтобы проект выглядел красиво, соответственно, удаляю временное и промежуточное в истории»

...

Смешно, что приходится сейчас выступать адвокатом дъявола и приводить аргументы, против которых я в прежних спорах горячо возражал, т.к. в области разработки я считают неизменность истории важнейшим критерием VCS :)

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

И снова на арене мы с git'ом...

И это только малая часть былых холиворов, часть их шла в сторонних темах, не моих :)

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

Так что игры с историей это дело тонкое.
Я бы так не делал.

Может, есть у кого-то иной, более подходящий инструмент тогда для решения такой задачи?

и если кто-то этим пользовался кроме тебя, ему предстоит весёлый merge

Вот это не нравится. Я думал, по прошлой рекламе git-адептов, что историю можно подправлять аккуратно. Неужели пример с правкой, скажем, пароля «задним числом» тоже приведёт к «весёлому merge»?

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

Я когда-то по ошибке закоммитил пароль/ключ API
Я делаю много временных мусорных коммитов, но хочу, чтобы проект выглядел красиво

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

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

но аргументы были, что история в git — это набор состояний с указателями/связями между ними. Ну, как элементы связного списка. И как в список можно вставлять новые элементы в любые позиции, так же позволяет и git.

Чексумма коммита зависит от парентов, поэтому смена указателя влечет изменение всех последующих коммитов, поэтому «вклеить страницу» не получится.

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

Вот это не нравится. Я думал, по прошлой рекламе git-адептов, что историю можно подправлять аккуратно. Неужели пример с правкой, скажем, пароля «задним числом» тоже приведёт к «весёлому merge»?

Да, тоже могут быть проблемы.

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

Но при этом нужно иметь в виду, что Git — это DVCS. Так что после исправления истории в одном месте это исправление необходимо распространить во все остальные клоны репозитория. Для чего понадобится содействие хозяев этих клонов.

ilammy ★★★
()
Последнее исправление: ilammy (всего исправлений: 1)
       --date=<date>
           Override the author date used in the commit.

Не подойдёт?

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

Сейчас, вот, потребовалась такая система, как раз. Но фанаты Git'а, которые прошлый раз мне убедительно доказывали, что в Git так можно (и иногда нужно), пока в теме не появлялись :)

тебе уже рассказали как сделать то что ты хочешь прямо в этой теме.

maloi ★★★★★
()

в принципе тут уже все написали, но повторю ещё раз - тебе нужен либо rebase (скорее всего с опциями --preserve-merges и --ignore-date) либо filter-branch.

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

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

не надо ничего переводить, git сам умеет дату нужную выставлять.

тем более непонятно в чем проблема :)

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

если кто-то этим пользовался кроме тебя, ему предстоит весёлый merge.

брехня. git pull --rebase в 99.9% случаев все делает автоматически без какого либо веселья.

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

почти согласен, в случае этого топика даже сработает, но вот в общем случае разгребать получившиеся merge может получиться запарно.

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

Вклеить страницу.

Если брать аналогию с журналом то rebase это выкинуть прошитый и опечатаный журнал и переписать заново как надо, прошить и опечатать.

что именно в такой гибкости и сила Git'а.

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

Это не коллективная работа с кодом. Это собственная система, задача которой не сохранение истории неизменной, а дополнение старой истории найденными позже артефактами.

Тогда переписывай сколько душе угодно, но помни, что тогда тебе надо на конечных узлах получать новую историю _полностью_

Dark_SavanT ★★★★★
()

если этот коммит - последний, то нет ничего проще, чем git commit --amend

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

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

почти согласен, в случае этого топика даже сработает, но вот в общем случае разгребать получившиеся merge может получиться запарно.

сначала надо чтобы таковые получившиеся merge получились каким-то образом. типично, им неоткуда взяться.

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

Может, есть у кого-то иной, более подходящий инструмент тогда для решения такой задачи?

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

Вот это не нравится. Я думал, по прошлой рекламе git-адептов, что историю можно подправлять аккуратно. Неужели пример с правкой, скажем, пароля «задним числом» тоже приведёт к «весёлому merge»?

Можно, но повторюсь, надо понимать что в этом случае переписывается вся поеледующая история. Весёлый merge происходит в том случае, если с, например, кодом активно работают разные люди и им придётся _явно_ делать rebase потому что их коммиты сделаны на основе «старой» истории.

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

Нетипичный пример: есть один известный проект, который раз в пару месяцев ветвится и master уезжает дальше, а в release приезжают исправления и иногда дополнения. release ветка может быть длинной и иногда даже «стабильной». Переезд с release на следующую release ветку задача интересная и зачастую полная неожиданностей. Это пример когда набираются весёлые мержи.

А откуда они берутся при rebase - я как-то раз бил по рукам товарищу, который feature branch хотел сделать красиво, а сделал через задницу поломав историю на remote.

Dark_SavanT ★★★★★
()

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

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

Вклеить страницу.

Гы-ы-ы-ы! Кажись мы совместными усилиями разработали простой тест на совместимость с гит.

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

Для этого нужно «сдвинуть» все рефы и испоганить reflog, а потом запустить сборку мусора. И даже в этом случае в небытиё уйдёт только энное количество последних коммитов. Вырезать кусок истории из гита невозможно.

В локальной копии хранятся даже данные, добавленные по git add (да-да-да, add пишет блобы в базу объектов).

а вопроса логики связей коммитов и работы с ними.

Для этого нужно прочитать одну главу из книжки Pro-git, емнип 9-ю, где описывается архитектура базы объектов гита.

что в Git так можно

Тебе же сразу написали решение через rebase. Оно прекрасно работает. И обладает устойчивостью от «неловких движений». Только генерит массу мусора, долго работает, и *действительно* переписывает всю историю, поменяв хеши коммитов.

Того же самого можно добиться через rebase -i: закоммитить в конец, а потом поменять порядок следования.

Тебя, наверное, смутили бранчи. Это бывает у пользователей сабвершена и меркуриала. В гите бранч — всего лишь ссылка на верхний коммит, а предыдущие значения пишутся в reflog.

Это не коллективная работа с кодом

Без разницы.

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

И как в список можно вставлять новые элементы в любые позиции, так же позволяет и git.

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

Macil ★★★★★
()

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

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

и вместо того чтоб научиться работать аккуратно и правильно они занимаются грязными вещами... мде

А что плохого в:

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

Если я всё это делаю в отдельных ветках, потом squash'у коммиты, cherry-pick'аю, редактирую историю в т. ч. делаю то, что хочет ТС и отправляю в master (или аналог) уже красивенькую линейку из коммитов?

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

А что плохого в:

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

подозреваю что человек не создаёт временные ветки с их последующим удалением
и это плохо
а ещё по хорошему перед мастером надо иметь ветку develop или stage

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

потом squash'у коммиты, cherry-pick'аю, редактирую историю

но зачем?
если вся команда следует одному workflow - проблем быть не должно
мне за 5 лет один раз пришлось делать rebase потому что баба-фронтэндер живёт в своём мире и про гит ничего знать не хочет, и ещё один случай я просто наблюдал со стороны, когда 2 разные команды почти без согласования работали над одной и той-же фичей

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

мне за 5 лет один раз пришлось делать rebase потому..

А как у вас история выглядит? Наверка же это помои вида {«фикс», «фикс», «ой б, забыл положить файл», «ой б, сборку сломал», «ещё один фикс вот к тому первому», ...}. В итоге получается на 1к рабочих SLOC дохренища неинформативных мусорных комитов.

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

В итоге получается на 1к рабочих SLOC дохренища неинформативных мусорных комитов.

Та же боль, но из под палки лучше не заставлять людей оформлять историю — они не понимают цели и смысла и такие косяки творят.

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