Git smudge/clean filter между ветвями
Есть много связанных вопросов, связанных с фильтрами smudge/clean - я потратил несколько часов на их чтение и пробовал различные варианты, но все еще не смог. Надеюсь, я могу спросить, каким образом я получаю ответ, который работает для меня.
В частности, я прочитал эту страницу на большинстве этих ответов, ссылаясь на:
TL;DR
Детальный вопрос, но резюме:
- Можно ли хранить
DEBUG = false
в файле в одной ветке и DEBUG = true
в другой ветке, используя фильтры smudge/clean для управления этим файлом? И как?
Фон
У меня есть разные удаленные репозитории, размещенные на битбакете. Я использую SourceTree на Win8, чтобы клонировать удаленные репозитории к моему ноутбуку. Я создаю разные ветки для разработки, функций, выпусков и т.д. (После успешная Git ветвящаяся модель для улучшения или хуже).
У меня есть класс Java java под названием Dbug.java
, который содержит логическое значение, которое включает/выключает различные протоколы отладки, mocking и т.д. в моем коде.
public static final boolean DEBUG = false;
Я хотел бы, чтобы это значение было false
в моей ветки "production" (master) и было true
в моих ветвях функций.
- Возможно ли использование фильтров, или я уже неправильно понял прецедент?
- Я не уверен, что фильтры работают так, как между двумя ветвями одного локально размещенного репо, или если фильтры работают только между двумя репозиториями.
Создание фильтров
Работая локально, я проверил производственную ветвь. Я создал тестовый файл с именем debug_flag.txt
со следующим содержимым:
// false on production branch
// true on other branches
DEBUG = false;
Я создал файл в корне моего локального репо под названием .gitattributes
и добавил ссылку на фильтр:
debug_flag.txt filter=debug_on_off
Я обновил файл .git/config
с помощью определения фильтра:
[filter "debug_on_off"]
clean = sed -e 's/DEBUG = true/DEBUG = false/'
smudge = sed -s 's/DEBUG = false/DEBUG = true/'
- В моем понимании это должно гарантировать, что у моего файла всегда есть
ложное значение в производстве, но будет иметь истинное значение, когда я перейду от
производство.
- Правильно ли это?
Тестирование фильтров
Я создал новую ветвь test
, используя:
git checkout -b test
Я проверил содержимое моего файла:
$ cat debug_flag.txt
// false on production branch
// true on other branches
DEBUG = false;
- Я ожидал увидеть значение
true
в файле
- Не должен ли фильтр "smudge" запускаться, когда я проверил файл?
Я добавил новую строку в файл и зафиксировал ее. Затем я переключился обратно в производственную ветвь, и здесь ситуация становится странной.
Если я смотрю на файл в SourceTree, никаких изменений в этой ветке с момента его создания нет. Этого я и ожидал бы, поскольку единственное изменение было сделано в другой ветке.
Если я смотрю на файл в терминале или Notepad ++, я вижу, что мое значение изменилось:
$ cat debug_flag.txt
// false on production branch
// true on other branches
DEBUG = true;
Я еще не объединил изменение между тестовой ветвью, я не сделал фиксацию на производственной ветке, но изменился файл.
- похоже, что фильтр smudge был запущен в файле внутри этой ветки, но не через ветки.
Мне не хватает жизненно важной части головоломки, и, надеюсь, это нечто простое, что может быть замечено кем-то, у кого есть опыт.
Моя ставка заключается в простом непонимании концепции.
Запрос Pls для любой отсутствующей информации...
Обновление на основе ответа VonC
Настройка базовых фильтров работала достаточно хорошо. Определили фильтр в файле config
следующим образом:
[filter "debug_on_off"]
clean = sed -e 's/DEBUG = true/DEBUG = false/'
smudge = sed -s 's/DEBUG = false/DEBUG = true/'
Создание новой ветки исправляет false → true, слияние обратно меняет true → false.
Завершение изменения только для производственной (основной) ветки требовало специальных скриптов, которые знали о ветке, из которой они выполняются. Таким образом, файл config
стал:
[filter "debug_on_off"]
clean = ./scripts/master_clean.sh
smudge = ./scripts/master_smudge.sh
master_clean.sh:
#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
if [ "master" = "$branch" ]; then
sed -e s/DEBUG = true/DEBUG = false/ $1
else
cat $1
fi
master_smudge.sh:
#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
if [ "master" = "$branch" ]; then
sed -e s/DEBUG = false/DEBUG = true/ $1
else
cat $1
fi
В этот момент я сталкиваюсь с несоответствиями между тем, что видит SourceTree, и тем, что показано в Notepad ++ для содержимого файла отладки. SourceTree показывает изменения, но Notepad ++ - нет.
Я принимаю ответ VonC, так как он отвечает на основной вопрос, который я задал.
Однако я, скорее всего, буду реализовывать решение которое я написал, поскольку он решает основную проблему, которую я пытаюсь решить, более простым способом (для меня): сохранение другого конфигурационного файла в отдельных ветвях.
Ответы
Ответ 1
Я ожидал увидеть значение true в файле
Вы только что создали новую ветку, не проверили ее содержимое (ее содержимое совпадает с той ветвью, в которой вы были)
Чтобы заставить смазку запустить, сделайте в верхней части репо:
git checkout HEAD --
Я еще не объединил это изменение с тестовой ветвью, я не сделал фиксацию в производственной ветки, но файл изменился.
Это идея драйвера фильтра содержимого: он изменяет контент, не затрагивая git status
(который все еще сообщает об измененном файле как "неизмененном" ).
Чтобы иметь размытие, действующее по-разному на каждую ветвь, я бы рекомендовал вызвать script, который начинается с поиска имени текущей ветки.
См. Пример в моем более раннем ответе "Лучшая практика - Git + Автоматизация сборки - Сохранение конфигураций отдельно.
#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
Ответ 2
Взгляните на expandr. Это script, который позволяет настраивать различные конфигурации на разных ветвях, используя smudge/clean. В основном именно то, что вы изначально запрашивали.
В настоящий момент самая большая проблема заключается в том, что после переключения ветвей иногда мне нужно сделать git checkout HEAD -- "$(git rev-parse --show-toplevel)"
, чтобы рабочий каталог был правильно смазан. В других случаях, однако, это работает нормально; Я еще не понял, почему. Я думаю, что это может быть связано с включением "merge renormalize", что вызывает некоторые проблемы? Я не уверен. (У меня оно есть.)
Другой способ заключается в том, что вы должны защищать каждую ветвь .gitattributes файлы сами с merge=ours
, помещая строку, в которой говорится .gitattributes merge=ours
, и, конечно же, включить драйвер для этого (как вы уже упоминали). gotcha заключается в том, что после создания каждой отдельной ветки теперь вы должны войти в каждый файл .gitattributes и изменить каждый из них (теперь я рекомендую добавить комментарий вроде #touched for merge=ours on master
, #touched for merge=ours on test branch
и т.д., так что вы помните, почему он был там). Вы должны сделать это, потому что merge=ours
будет защищать файл только от изменения в версии входящей ветки в слиянии, если этот файл был изменен после создания ветки как в входящей ветки, так и в ее родительской ветке. (Помните, что git имеет дело с изменениями, а не с файлами.)
Ответ 3
Совет VonC описывает точный вопрос, который я задал, но мне не удалось определить окончательные детали (согласно моему обновлению на вопрос). Этот ответ дает подробные сведения о том, как я это сделал.
Update
Ниже метод работал для первого слияния. Но после этого он больше не работает. Я оставляю его здесь, так как он представляет текущее состояние моего расследования.
Кажется, что драйверы слияния больше не вызываются.
Также попробовали различные модификации связанных вопросов с помощью exit 0
, touch %A
или пользовательского script слияния (fooobar.com/questions/6109/...) вместо true
, как показано ниже.
Я нашел обходной путь к этому, который использует настраиваемую стратегию merge
для решения основной проблемы, которая:
- Я хочу, чтобы файлы сборки в моей ветке сборки всегда устанавливались, чтобы отключить все значения отладки.
- Это предотвращает случайные выпуски продукта с настройками макета, настройками локального хоста, ведением журнала и т.д.
Я основываюсь на информации по этому вопросу: .gitattributes и индивидуальная стратегия слияния для файла
1)
Определите пользовательский драйвер слияния в файле .git/config
следующим образом:
[merge "ours"]
name = "Keep ours merge"
driver = true
Я не уверен, нужен ли этот шаг - но кажется, что это может быть обходным путем для ошибки в некоторых (более старых?) системах.
(для деталей: fooobar.com/questions/9401/...)
2)
Настройте файл .gitattributes
в ветке build/production/pristine, чтобы специальный флаг отладки использовал вышеупомянутую стратегию слияния.
Поэтому, используя файлы в моем вопросе, перейдите в ветвь "production" и добавьте следующую строку в файл .gitattributes
:
debug_flag.txt merge=ours
Каждый раз, когда слияние возвращается в ветвь "production", git будет искать стратегию слияния, определенную как "наш", и будет препятствовать перезаписыванию debug_flag.txt.
3)
На других ветвях настройте свой .gitattributes
файл без этой стратегии слияния.
4)
Последний (но важный) шаг процесса конфигурации - правильно настроить файл debug_flag.txt во всех ветвях и фиксировать изменения в каждой ветке.
Теперь у вас должно быть 2 ветки, каждая из которых содержит разные версии файлов .gitattributes
и debug_flag.txt. Это гарантирует, что при каждом слиянии возникают конфликты.
Без конфликтов обычная стратегия слияния "наш" не вызывается, и файлы могут быть перезаписаны.
(для деталей: fooobar.com/questions/9401/...)
5)
Наконец, объедините свою новую ветку в "производство". У вас возникнут конфликты слияния из-за шагов 3 и 4. Разрешите конфликты, чтобы 2 ветки сохраняли свои различия. Зафиксируйте изменения.
Все будущие слияния этих двух ветвей без проблем будут игнорировать файл debug_flag.txt.
Это позволяет создать 2 разных файла конфигурации на разных ветвях, чтобы вы могли легко отделить отладку от производственного кода и т.д. Это, похоже, является распространенным вариантом использования, со многими связанными с ним вопросами на этом форуме, но он по-прежнему мне пару дней, чтобы понять это.
Ответ 4
Самое прямолинейное решение - обновить ваш make файл, чтобы включить проверку того, какая ветка в данный момент проверена. Если ветвь является частью именованного списка, определите новый аргумент build -DDEBUG = true или -DDEBUG = false в противном случае.
См. Как программно определить текущую вывешенную ветвь Git
branch_name=$(git symbolic-ref -q HEAD)
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD}
PROD_BRANCHES := master \
QA
debug_flag=
ifneq ($(filter $(branch_name),$(PROD_BRANCHES)),)
debug_flag="-DDEBUG=true"
endif
ifeq($debug_flag,)
debug_flag="-DDEBUG=false"
endif