Избегайте перекомпиляции с помощью git и выполните
У меня две ветки развития в git, и мне часто приходится менять между ними. Тем не менее, действительно разочаровывает то, что каждый раз, когда я меняю ветки в git, весь проект перестраивается, потому что временные метки файловой системы для некоторых файлов будут меняться.
Ofc, make файлы сконфигурированы для создания проекта в два разных каталога компоновки.
Есть ли способ обойти это? Компиляция - очень длительный и трудоемкий процесс...
Изменить: - Это немного более подробное объяснение вопроса...
Скажем, у меня есть файлы заголовков Basic.h, которые включены в ряд других файлов. Basic.h отличается от ветки 1 и ветки 2.
Теперь скажем, что я скомпилировал ветвь 1 в build_branch1 и ветку 2 в build_branch2. Скажем, у меня есть филиал 2, который в настоящее время проверен. Теперь я проверяю ветку 1 и меняю File1.cpp и перекомпилирую. В идеале, поскольку только File1.cpp изменился с тех пор, как я скомпилировал его в последний раз, это единственный файл, который нужно перекомпилировать.
Однако, поскольку у параметра Basic.h его временная метка изменилась из-за проверки, все файлы, содержащие Basic.h, будут перекомпилированы. Я хочу избежать этого.
Ответы
Ответ 1
Git изменяет только файлы, которые обновляются между ветвями. Но если ваш компилятор выполняет полную перестройку, даже если какой-либо один файл был изменен, вы всегда можете клонировать и проверять свои разные ветки на разные каталоги. То вроде:
/your-repo-name.branch1
/your-repo-name.branch2
Это занимает дополнительное дисковое пространство, но гораздо удобнее, чем переключение расходящихся ветвей в огромное репо.
Ответ 2
Другой частичный ответ: кэш компилятора.
Когда вы переключаетесь обратно на исходную ветвь и перестраиваете, хотя зависимости говорят о том, что многие файлы, зависящие от Basic.h
, должны быть перестроены, объектные файлы можно вытащить из кеша компилятора.
ccache
(http://ccache.samba.org/) по-прежнему приходится выполнять довольно дорогостоящую работу (обработка предварительно обработанной единицы перевода, поскольку вся единица перевода используется хеш-ключ), но это намного дешевле, чем компиляция.
В некоторых случаях ccache
может устранить компиляцию перед лицом изменения, которое не влияет на нее, например, некоторые изменения пробелов. Например, если вы изменяете комментарий в зависимом файле (заголовок или источник), это не делает недействительным файл кэшированного объекта.
Так что это может помочь, даже если вы делаете git pull
и выбираете новое изменение на Basic.h
, которое вы раньше не видели.
Ответ 3
Если вы знаете, какие файлы на самом деле нуждаются в компиляции, и делайте их вручную, GNU Make (по крайней мере, я не знаю о других реализациях ) имеет для вас флаг: -t
, который в основном работает над вашим файлом Makefile и изменяет временные метки вместо запуска команд.
Вам все равно нужно обновить файлы, которые необходимо обновить, перед использованием этого флага, или вы получите объектные файлы, которые законно устарели, но выглядят обновленными. Подробнее см. Связанный документ.
Опция -o
также может вас заинтересовать, в зависимости от того, сколько изменений при переключении ветвей.
Ответ 4
Нет никакого хорошего способа сохранить временные метки и не столкнуться с проблемами в вашей среде сборки. Используйте git clone/git checkout branchB, чтобы создать второй рабочий каталог для построения и работы с ветвью B. У вас нет сборки Makefile, каждая из них встроена в свой собственный каталог сборки.
Ответ 5
Если Basic.h
на самом деле отличается между ветвями, то единственным решением является разбить его на более мелкие файлы с более мелкозернистыми зависимостями, чтобы меньшее количество файлов было перестроено при его изменении.
Но предположим, что Basic.h
на самом деле точно совпадает между ветвями, но git
меняет свою метку времени. Это ложный триггер, например, touch Basic.h
, который показывает ограничение систем построения на основе временных меток. В идеале мы хотим, чтобы система сборки восстанавливалась при изменении содержимого, а не при изменении временных меток. Временные метки используются, потому что они являются дешевой заменой для обнаружения изменения контента. Высший метод заключается в том, чтобы система сборки сохраняла хэши всех файлов и обнаруживала фактические изменения без учета отметки времени. Это также устраняет проблемы, такие как "обнаружение перекоса часов, ваша сборка может быть неполной".
Вы не собираетесь получать такую систему сборки из Make; но вы можете работать с некоторыми его аспектами в отношении определенных файлов. Например, вы можете написать свои правила Make, чтобы ваши объектные файлы не зависели напрямую от Basic.h
, а от Basic.h.sha
, который является файлом штампа. Теперь, что находится в Basic.h.sha
? Этот файл содержит хэш SHA256 Basic.h
.
Каждый раз, когда вы запускаете Make, логика в Makefile вычисляет хэш над Basic.h
и сравнивает его с хешем, хранящимся в Basic.h.sha
. Если они отличаются, то Basic.h.sha
перезаписывается новым хэшем. Таким образом, его временная метка сталкивается, вызывая восстановление.
BASIC_H_SHA := $(shell sha256sum Basic.h)
BASIC_H_SHA_OLD := $(shell cat Basic.h.sha)
ifneq ($(BASIC_H_SHA),$(BASIC_H_SHA_OLD))
$(info Basic.h has changed!)
DUMMY := $(shell echo "$(BASIC_H_SHA)" > Basic.h.sha)
endif
Я реализовал логику в этих строках, чтобы модули зависели от изменений в их соответствующих CFLAGS
. В принципе, мы можем превратить изменение во что угодно в прикосновение к файлу timestamp, который контролирует то, что построено.