Может ли git игнорировать определенную строку?

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

var isPhoneGap = false;

Очевидно, я меняю это при сборке, но есть ли способ настроить git, чтобы игнорировать эту единственную строку, или мне нужно пойти и поместить ее в отдельный файл и игнорировать ее таким образом?

Я использую Gitx и терминал на OSX 10.6.


person Iolo    schedule 02.07.2011    source источник
comment
@ user494461: фильтры Git - это способ сделать это: stackoverflow.com/a/16244970/520162   -  person eckes    schedule 03.03.2014
comment
Вы не можете обнаружить среду и использовать файл конфигурации eniroment?   -  person exussum    schedule 04.03.2014
comment
Вкратце: нет. Но я написал сценарий препроцессора, который ищет определенный закомментированный код и удаляет его перед публикацией в git. Проверьте это здесь: github.com/franklinchou/ahk_config/blob/master/preprocess .sh   -  person franklin    schedule 21.11.2015


Ответы (9)


Если ваш файл относится к определенному типу, вы можете объявить драйвер фильтра содержимого, который можно объявить в .gitattributes файле ( как представлено в расширении ключевых слов Атрибуты Git ):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(вы даже можете установить этот фильтр для определенного файла, если хотите)

Воплощать в жизнь:

  • yourFilterName.smudge (сработало git checkout) и

      git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean (сработало git add)

      git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

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


Примечание: в комментариях, ohaal и Роальд предлагают чтобы изолировать sed вызовы в отдельном helper.sh скрипте:

sed "s/isPhoneGap = .*/isPhoneGap = true/" "$@"
person VonC    schedule 04.03.2014
comment
Спасибо за это. получил это работает. Вы знаете, как сделать git diff or git status`, но игнорировать фильтры? Так что я все еще вижу, что изменилось? Мой вариант использования - журналы отладки ... которые в конечном итоге я хочу удалить ... @jthill @VonC - person timh; 27.03.2014
comment
@timh, если фильтр работает, git status или git diff ничего не должны показывать. - person VonC; 27.03.2014
comment
жаль, что в GIT нет более простого способа. git ignore ‹filename› ‹linenumber› будет так кстати! - person kiedysktos; 14.09.2016
comment
@kiedysktos льняной номер? Что делать, если номер строки изменится? - person VonC; 14.09.2016
comment
Это отлично сработало, но будьте осторожны, пользователи Windows, gitconfig очень разборчив с тем, какие символы он хочет содержать, поэтому при попытке использовать некоторые полуэкзотические регулярные выражения вы можете столкнуться с проблемами. В итоге я поместил свои вызовы sed в отдельный файл helper.sh, который я вызвал из своего gitconfig с sh ".git/helper.sh", убедившись, что все параметры передаются в sed с "$@" (я предполагаю, что передан только путь к файлу). - person ohaal; 26.06.2018
comment
@ohaal Хороший вопрос. В таких случаях зачастую проще использовать сценарий. - person VonC; 26.06.2018
comment
helper.sh тогда содержимое будет: sed "s/isPhoneGap = .*/isPhoneGap = true/" "$@" - person Roald; 08.09.2020
comment
@Roald Спасибо за отзыв. Я включил ваш комментарий в ответ для большей наглядности. - person VonC; 08.09.2020
comment
@VonC, возможно, комментарии в коде? Фильтрация также кажется опасной, так как позволяет получить больше строк с одним и тем же шаблоном. - person João Pimentel Ferreira; 12.07.2021
comment
@ JoãoPimentelFerreira Я согласен: вам нужен достаточно конкретный шаблон, чтобы выбрать только то, что вы ожидаете. Не всегда гарантия. - person VonC; 12.07.2021

Ты можешь использовать

git update-index --assume-unchanged [file]

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

Когда в файле есть важные изменения, вам необходимо сделать следующее:

git update-index --no-assume-unchanged [file]

Также см. Git doc update-index для параметра --[no-]assume-unchanged.

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

person Carlos    schedule 11.07.2012
comment
Будет ли это по-прежнему получать новую версию, когда я выполняю git pull? - person Saad Rehman Shah; 08.11.2012
comment
@Caffeine, когда вы выполняете git pull, вы получаете последнюю версию, которая была зафиксирована, это будет последняя версия перед тем, как вы измените файл на --assume-unchanged. - person Carlos; 16.11.2012
comment
Я считаю, что --skip-worktree - лучший вариант для большинства целей. stackoverflow.com/a/39583010/4233593 - person Jeff Puckett; 11.04.2018
comment
это игнорирует обновления всего файла, а не отдельной строки - person nikoss; 08.09.2019

Gitx должен позволять вам фиксировать или игнорировать отдельные строки (вы, возможно, уже знаете об этом), но вам придется делать это каждый раз, когда вы фиксируете. Я думаю, что было бы лучше иметь файл конфигурации для каждой цели развертывания (вы можете версия для них) и некоторый параметр времени выполнения, независимо от того, запускаете ли вы сервер (например, ./myserver --config=whatever.js).

person Andy Ray    schedule 02.07.2011

Продолжая https://stackoverflow.com/a/20574486/4935114, @ Mike предложил создать pre-commit ловушку, которая grep будет в промежуточных файлах для строк, которые можно игнорировать. Хук проверяет, были ли эти строки поставлены. Если да, то это echo предупреждение и exit код 1, поэтому процесс фиксации не будет продолжен.

Вдохновленный ответом Майка, я обнаружил, что использую, возможно, улучшенную версию его крючка, который автоматически resets (с флагом -p) конкретная строка, которую мы хотим игнорировать.

Я не уверен, что этот хук будет работать в ситуации, когда у вас есть много файлов с этой строкой, которые нужно игнорировать, но этот pre-commit хук ищет изменения в этой строке в конкретном файле buildVars.java. Скрипт перехвата выглядел так, когда я тестировал его на своей машине.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Объяснение

Я повторил контрольные последовательности, которые ищут регулярное выражение isPhoneGap во время интерактивного reset процесса. Таким образом, имитируя пользователя, который нажимает / для поиска isPhoneGap, нажимает y, когда его спрашивают, хочет ли он отменить этот патч, и наконец нажимает q для выхода из интерактивного reset.

Интерактивный обратный процесс исправления документирован здесь: https://git-scm.com/docs/git-add#git-add-patch.


ПРИМЕЧАНИЕ. В приведенном выше сценарии предполагается, что переменная interactive.singleKey - это false. Если вы настроили свой на true, удалите любой $'\n' из команды echo сразу после предупреждения.

person Doron Behar    schedule 05.09.2017

Вот как это можно сделать с помощью фильтров git < / а>:

  1. Create/Open gitattributes file:
    • <project root>/.gitattributes (will be committed into repo)
      OR
    • ‹Корень проекта> /. Git / info / attributes (не будет зафиксирован в репо)
  2. Add a line defining the files to be filtered:
    • *.rb filter=gitignore, i.e. run filter named gitignore on all *.rb files
  3. Define the gitignore filter in your gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d", i.e. delete these lines
    • $ git config --global filter.gitignore.smudge cat, т.е. ничего не делать при извлечении файла из репо

Примечания:
Конечно, это для файлов ruby, применяется, когда строка заканчивается на #gitignore, применяется глобально в ~/.gitconfig. Измените это, как вам нужно для ваших целей.

Предупреждение !!
Это оставляет ваш рабочий файл отличным от репо (конечно). Любая проверка или перестановка будут означать, что эти строки будут потеряны! Этот прием может показаться бесполезным, поскольку эти строки постоянно теряются при извлечении, перемещении или извлечении, но у меня есть конкретный вариант использования, чтобы его использовать.

Просто git stash save "proj1-debug" пока фильтр неактивен (просто временно отключите его в gitconfig или что-то в этом роде). Таким образом, мой отладочный код всегда может быть git stash apply присоединен к моему коду в любое время, не опасаясь, что эти строки когда-либо будут случайно зафиксированы.

У меня есть возможная идея решения этих проблем, но я попробую реализовать ее в другой раз.

Спасибо Руди и jw013 за упоминание фильтров и атрибутов git.

person Kache    schedule 26.04.2013

Драйвер фильтра содержимого - не лучшее решение. Вы можете скрыть эту строку из git status / etc, но на самом деле она не игнорируется. Как только вы измените значение, ваш рабочий каталог будет помечен как грязный, даже если изменение может быть не видно.

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

person patricktokeeffe    schedule 28.05.2014
comment
Как только вы измените значение, ваш рабочий каталог будет помечен как грязный, даже если изменение может быть невидимым: этого не должно быть, если чистый сценарий все еще восстанавливает файл в его исходном содержании. - person VonC; 28.05.2014
comment
Я так и думал. Я использую GitExtensions, и он покажет файл как измененный, даже если панель различий пуста. Возможно, потому что чистый фильтр не запускается до возврата файла. Возможно, потому что это msysgit, а не git-git. ИДК, ЯММВ - person patricktokeeffe; 29.05.2014

Я предполагаю, что это может быть что-то, что встречается более чем в одной строке вашего источника.

Я думаю, что было бы лучше всего иметь какой-то файл .userbuildconfig, который вы просто включаете и проверяете значения по умолчанию. Затем вы можете использовать Предложение Карлоса пометить только этот файл как предполагаемый без изменений. Таким образом не будут пропущены другие изменения в файле, в котором нужно проверить настройку.

Это может позволить вам настраивать макросы препроцессора локально (или для java что-то вроде этого https://stackoverflow.com/a/1813873/1270965 < / а>).

person johnb003    schedule 07.03.2014

Неа. Вы можете игнорировать только отдельные файлы (и многое другое), поскольку строки в .gitignore соответствуют именам файлов, а не содержимому файла. Вы уже упомянули решение этой проблемы, то есть игнорируйте один файл, содержащий тот контент, который вы хотите игнорировать.

person ralphtheninja    schedule 03.07.2011
comment
Я согласен, в моем случае было достаточно и возможно просто включить этот контент из проигнорированного файла. Так что перемещаем все игнорируемые настройки. там. Кроме того, я создал копию этого проигнорированного файла и добавил ее в индекс в качестве ссылки, поэтому информация о том, что должно быть в этом файле, не будет потеряна. - person Urs; 04.03.2016

Я думаю, что никто не предоставил такой способ решения проблемы, так что вот мой метод. Я веду журнал / отладку и т. Д. В одной ревизии (на самом деле, их может быть несколько) в частной ветке в моем локальном репо. Итак, когда я запускаю функциональную ветку и хочу иметь все свои плюшки (в ветке my-goodies), я просто делаю следующее:

git checkout my-feature
git cherry-pick my-feature..my-goodies # assuming both started from the same main branch, say, my-goodies started a few (or many) revisions back

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

git rebase -i @{u} # set all the goodies revisions to skip, save, and go

Теперь моя ветка чиста от всех моих вкусностей, и я могу пихать куда угодно.

person eftshift0    schedule 07.06.2021