Мерзкое пятно / чистый фильтр между ветвями

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

В частности, я прочитал страницу, на которую ответили большинство ответов:


ТЛ; др

Это подробный вопрос, но резюме таково:

  • Могу ли я хранить DEBUG = false в файле на одной ветке, и DEBUG = true в другой ветке, используя smudge/clean filters для управления этим файлом? И как?

Фон

У меня есть различные удаленные репозитории, размещенные на bitbucket. Я использую SourceTree на Win8, чтобы клонировать удаленные репозитории на моем ноутбуке. Я создаю различные ветки для разработки, функций, выпусков и т. Д. (Следуя успешной модели ветвления Git, в лучшую или в худшую сторону).

У меня есть Android-класс Java под названием Dbug.java он содержит логическое значение, которое включает / отключает различные функции ведения журнала отладки, насмешек и т. д. в моем коде.

public static final boolean DEBUG = false;

Я хотел бы, чтобы это значение было false на моей "производственной" (основной) ветке, и быть 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 был запущен для файла в пределах этой ветви, но не между ветвями.

Мне не хватает жизненно важной части головоломки, и, надеюсь, это что-то простое, что может заметить кто-то с опытом, делающим это.

Держу пари, это простое недопонимание концепции.

Просьба подсказать любую недостающую информацию...


Обновление на основе ответа 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, поскольку он отвечает на основной вопрос, который я поставил.

Тем не менее, я, вероятно, буду реализовывать решение, которое я написал, так как оно решает основную проблему, которую я пытаюсь решить, более простым (для меня) способом: сохранение другого файла конфигурации в отдельных ветвях.

5 ответов

Решение

Я ожидал увидеть значение true в файле

Вы только что создали новую ветку, а не извлекли ее содержимое (так как ее содержимое совпадает с тем, в котором вы были)

Чтобы заставить пятно бежать, сделайте в верхней части репо:

git checkout HEAD --

Я еще не объединил изменения с тестовой веткой, я не сделал коммит в рабочей ветке, но файл изменился.

В этом идея драйвера фильтра контента: он изменяет контент, не затрагивая git status (который все еще сообщает об измененном файле как "без изменений").

Чтобы пятно действовало по-разному для каждой ветви, я бы порекомендовал вызвать скрипт, который начинается с просмотра названия текущей ветви.
См. Пример в моем предыдущем ответе " Лучшая практика - Git + Build Automation - Хранение конфигов отдельно".

#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)

Рекомендация VonC касается точного вопроса, который я поставил, но я не смог определить окончательные детали (согласно моему Обновлению вопроса). Этот ответ дает подробности того, как я сделал вещи.


Обновить

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

Кажется, что драйверы слияния больше не называются.

Также пробовал различные модификации от связанных вопросов, используя exit 0, touch %Aили пользовательский драйвер слияния сценариев ( /questions/34464398/kak-mne-skazat-git-vsegda-vyibirat-moyu-lokalnuyu-versiyu-dlya-konfliktuyuschih-sliyanij-v-konkretnom-fajle/34464401#34464401) вместо true как представлено ниже.


Я нашел обходной путь к этому, который использует обычай merge Стратегия для решения основной проблемы, которая является:

  • Я хочу, чтобы файлы сборки в моей ветке сборки всегда были отключены.
  • Это предотвращает случайные выпуски продукта с фиктивными настройками, настройками локального хоста, включенным ведением журнала и т. Д.

Я основал следующую информацию на этом вопросе: .gitattributes и индивидуальная стратегия слияния для файла

1) Определите пользовательский драйвер слияния в .git/config файл следующим образом:

[merge "ours"]
    name = "Keep ours merge"
    driver = true

Я не уверен, требуется ли этот шаг, но кажется, что это может быть обходной путь для ошибки в некоторых (более старых?) Системах.

(для деталей: /questions/38299303/gitattributes-and-otdelnaya-strategiya-sliyaniya-dlya-fajla/38299319#38299319)

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 файлы. Это гарантирует, что при каждом слиянии возникают конфликты.

Без конфликтов пользовательская "наша" стратегия слияния не вызывается, и файлы могут быть перезаписаны.

(для деталей: /questions/38299303/gitattributes-and-otdelnaya-strategiya-sliyaniya-dlya-fajla/38299313#38299313)

5) Наконец, объедините вашу новую ветку с "производством". У вас будут конфликты слияния из-за шагов 3 и 4. Разрешите конфликты так, чтобы две ветви сохранили свои различия. Зафиксируйте изменения.

Все будущие слияния между этими двумя ветвями будут без проблем игнорировать файл debug_flag.txt.


Это решает задачу иметь 2 разных конфигурационных файла в разных ветках, так что вы можете легко отделить отладку от производственного кода и т. Д. Это, похоже, распространенный случай, со многими связанными вопросами на этом форуме, но мне все равно понадобилась пара дней, чтобы сделать это правильно.

Посмотрите на расширитель. Это скрипт, который позволяет вам устанавливать разные конфиги в разных ветках, используя smudge / clean. В основном именно то, что вы изначально просили.

Сейчас самая большая проблема в том, что после переключения веток иногда мне нужно git checkout HEAD -- "$(git rev-parse --show-toplevel)" чтобы рабочий каталог был правильно смазан. В других случаях, однако, это, кажется, работает хорошо; Я еще не понял, почему. Я думаю, что это может иметь отношение к включенному "слиянию перенормировать", вызывая некоторые проблемы? Я не уверен. (У меня это есть.)

Другой недостаток заключается в том, что вы должны защищать файлы.gitattributes каждой ветви сами merge=ours поставив строку в том, что говорит .gitattributes merge=ours и, конечно, для этого нужно включить драйвер (как вы уже упоминали). Гвоздь здесь в том, что после того, как вы создаете каждую отдельную ветку, теперь вы должны войти в каждый файл.gitattributes и изменить каждый (я рекомендую теперь добавить комментарий как #touched for merge=ours on master, #touched for merge=ours on test branchи т. д., так что вы будете помнить, почему это было там). Вы должны сделать это, потому что merge=ours будет защищать файл от изменения версии входящей ветви в слиянии, только если этот файл был изменен после создания ветви как на входящей ветви, так и на ее родительской ветви. (Помните, что git имеет дело с изменениями, а не с файлами.)

Самым простым решением было бы обновить ваш make-файл, включив в него проверку того, какая ветка в настоящий момент извлечена. Если ветвь является частью именованного списка, определите новый аргумент сборки -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

У меня есть аналогичный вариант использования, и я смог решить его с помощью фильтра и крючка после оформления заказа. Хук хорош, потому что он очищает + размазывает за вас и немедленно обновляет файл при переключении веток через GitHub Desktop. При таком подходе каждая песочница / уровень имеет свою собственную конфигурацию для каждой ветки.

Подробное описание на: https://c1.eagen.net/git-smudge-clean.html

Образец репозитория по адресу: https://github.com/vinnyjames/git-filter-demo.git

Другие вопросы по тегам