rsync виключити відповідно до .gitignore & .hgignore & svn: ігнорувати як --filter =: C


113

Rsync включає в себе чудовий варіант --cvs-exclude"ігнорувати файли так само, як це робить CVS", але CVS вже застаріли роками. Чи є якийсь спосіб зробити так само виключення файлів, які сучасні системи контролю версій (Git, Mercurial, Subversion) ігнорували б?

Наприклад, у мене є багато проектів Maven, перевірених у GitHub. Зазвичай вони включають в себе .gitignoreщонайменше список target, каталог за замовчуванням Maven build (який може бути присутнім на верхньому рівні або в підмодулях). Оскільки вміст цих каталогів повністю одноразовий, і він може бути набагато більшим, ніж вихідний код, я хотів би виключити їх при використанні rsync для створення резервних копій.

Звичайно, я можу явно, --exclude=target/але це випадково придушить не пов'язані між собою каталоги, які просто трапляються названими targetі не повинні ігноруватися.

І я міг би надати повний список абсолютних шляхів для всіх імен файлів та зразків, згаданих у будь-якому .gitignore, .hgignoreабо svn:ignoreвластивості на моєму диску, але це був би величезний список, який повинен був би бути створений за допомогою якогось сценарію.

Оскільки rsync не має вбудованої підтримки для оформлення замовлень VCS, окрім CVS, чи є якийсь хороший трюк для її подачі їх моделей ігнорування? Або якась система зворотного виклику, за якою в сценарію користувача можна запитати, чи повинен бути вказаний файл / каталог чи ні?

Оновлення : --filter=':- .gitignore'як вважає LordJavac, здається, працює також добре для Git, як --filter=:Cі для CVS, принаймні на прикладах, які я знайшов, хоча незрозуміло, чи синтаксис точно відповідає. --filter=':- .hgignore'не дуже добре працює для Mercurial; наприклад, що .hgignoreмістить рядок типу ^target$(Mercurial еквівалент Git /target/) rsync не розпізнає як регулярний вираз. І, здається, ніщо не працює для Subversion, для якої вам доведеться розібратися .svn/dir-prop-baseв робочій копії 1.6 або попередньої версії, і з жахом кинути руки на робочу копію 1.7 або пізнішої версії.


11
Здається трохи, як було б непогано надіслати патч для rsync, який додає підтримку .gitignore, .hgignore тощо.
ThiefMaster

3
@TentistMaster: Я подав bugzilla.samba.org/show_bug.cgi?id=9744 як вихідну точку.
Джессі Глік

2
лише примітка для інших, .gitignore має бути в ієрархії папок, будучи rysnc'd, а не в каталозі, що команда виконується
myol

Що :-саме означає? Що означає товста кишка? Що тире?
Девід

Тепер у Git є check-ignoreпідкоманда, яка може вирішувати важку роботу з розбору різних «ігнорувати» файлів, якщо ви хочете перейти до параметра «створити список усіх неігнорованих» файлів. Моя відповідь тут дає детальну інформацію про те, як це зробити.
cjs

Відповіді:


120

Як згадував luksan, це можна зробити за допомогою --filterпереключення на rsync. Я домігся цього за допомогою --filter=':- .gitignore'(перед ".gitignore") є пробіл, який говорить rsyncпро об'єднання каталогів з .gitignoreфайлами та їх виключення за правилами git. Ви також можете додати свій глобальний файл ігнорування, якщо у вас є. Щоб полегшити використання, я створив псевдонім, до rsyncякого входив фільтр.


Хороший початок, хоча я вагаюся "прийняти" цю відповідь, оскільки вона стосується лише Git.
Джессі Глік

23
Більш деталізована версія, яка також виключає .git файли:--exclude='/.git' --filter="dir-merge,- .gitignore"
VasiliNovikov

2
У мене є щось подібне зараз: rsync -rvv --exclude='.git*' --exclude='/rsync-to-dev.sh' --filter='dir-merge,-n /.gitignore' $DIR/ development.foobar.com:~/test/.. але, хоч воно і говорить [sender] hiding file .gitignore because of pattern .git*, файл все-таки надсилається на дезінацію
rolandow

2
Якщо ви хочете використовувати --deleteваріант, тут працює з командного рядка: rsync --delete-after --filter=":e- .gitignore" --filter "- .git/" -v -a .... Це знадобило мені деякий час ... eу фільтрі, і --delete-afterвони обидва важливі. Пропоную прочитати розділ людини "ПЕРЕГРЯДНІ ПРАВИЛА ТА УВАГА" rsync.
дболотін

1
Щоб синхронізувати видалення, а також додавання та оновлення, ви можете просто додати --delete-afterдо @ VasiliNovikov версії команди. (Це здається еквівалентним версії команди @ dboliton, за винятком @db використовує: e, що, на мою думку, виключає копіювання файлів .gitignore. Це не те, що я хотів.)
Bampfer

10

Ви можете використовувати git ls-filesдля створення списку файлів, виключених з файлів сховища .gitignore. https://git-scm.com/docs/git-ls-files

Параметри:

  • --exclude-standardРозглянемо всі .gitignoreфайли.
  • -o Не ігноруйте нестандартні зміни.
  • -i Виводити лише ігноровані файли.
  • --directory Вивести шлях до каталогу лише у випадку, якщо весь каталог проігноровано.

Єдине, що мені залишилося ігнорувати, було .git.

rsync -azP --exclude=.git --exclude=`git -C <SRC> ls-files --exclude-standard -oi --directory` <SRC> <DEST>

4
це не працює. він виключає перший файл із підкоманди git, а потім розглядає решту як частину списку SRC. це працює: rsync -azP --exclude-from="$(git -C SRC ls-files --exclude-standard -oi --directory > /tmp/excludes; echo /tmp/excludes)" SRC DEST
марафон

2
Це єдиний метод, який працює, якщо ви виключаєте і включаєте рядки у свій .gitignore(тобто рядки, що починаються з !). Це також файли rsyncs, які ви --forceдодали до репо, що зазвичай є хорошою справою.
ostrokach

1
Дійсно ця відповідь НЕ ПРАЦЮЄ, тож я закінчив писати той, що працює: stackoverflow.com/a/50059607/99834
sorin

6

як щодо rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination?
Це працювало для мене.
Я вірю, що ти можеш мати і більше --exclude-fromпараметрів.


3
Це буде працювати, якщо у ваших .gitignoreфайлах трапляється використовувати синтаксис, сумісний із rsync.
Джессі Глік

@JesseGlick прав, Rsync НЕ в змозі розібрати .gitignore файлів см stackoverflow.com/a/50059607/99834 workround.
sorin

6

Рішення 2018 року підтверджено

rsync -ah --delete 
    --include .git --exclude-from="$(git -C SRC ls-files \
        --exclude-standard -oi --directory >.git/ignores.tmp && \
        echo .git/ignores.tmp')" \
    SRC DST 

Деталі: --exclude-fromобов'язкові замість --exclude, оскільки ймовірний випадок, що виключає список, не буде аналізуватися як аргумент. Виключити з потрібного файлу та не може працювати з трубами.

Поточне рішення зберігає файл виключення всередині папки .git, щоб переконатися, що це не вплине git status, зберігаючи його самостійно. Якщо ви хочете, можете використовувати / tmp.


3
Схоже, це буде спрацьовувати, якщо у вас є конкретне сховище Git, яке ви хочете синхронізувати - SRCтут - але не для первісної проблеми, про яку я заявив, це розповсюджений каталог з тисячами репозиторіїв Git як підкаталоги на різних глибинах, багато з яких мають ідіосинкратичний .gitignoreс.
Джессі Глік

1
Якщо ви використовуєте оболонку з підтримкою заміни процесу (bash, zsh тощо), ви можете використовувати--exclude-from=<(git -C SRC ls-files --exclude-standard -oi --directory)
Roland W

3

Для ртутний можна використовувати

hg status -i | sed 's/^I //' > /tmp/tmpfile.txt

зібрати список файлів, які НЕ перебувають під контролем ртутного контролю через обмеження .hgignore, а потім запустіть

rsync -avm --exclude-from=/tmp/tmpfile.txt --delete source_dir/ target_dir/

для rsync всіх файлів, крім ігнорованих. Зауважте -m прапор у rsync, який виключатиме синхронізацію порожніх каталогів, оскільки статус hg -i перераховуватиме лише виключені файли, не dirs


2

Спробуйте це:

rsync -azP --delete --filter=":- .gitignore" <SRC> <DEST>

Він може скопіювати всі файли у віддалений каталог, за винятком файлів у ".gitignore", та видалити файли, які не є у вашому поточному каталозі.


1

На rsyncголовній сторінці, крім стандартного списку шаблонів файлів:

Файли, перелічені в $ HOME / .cvsignore, додаються до списку та будь-які файли, перелічені у змінній середовища CVSIGNORE

Отже, мій файл $ HOME / .cvsignore виглядає так:

.git/
.sass-cache/

щоб виключити .git та файли, створені Sass .


2
Навпаки, я точно хочу включити .git/каталоги, можливо, навіть сильніше, ніж робочу копію. Те, що я хочу виключити, - це побудова продукції.
Джессі Глік

Також ця настройка не є портативною. Це на кожного користувача, а не на проект.
ВасильНовіков

@JesseGlick Я відвертаю вас щодо того, щоб увімкнути .git / dirs включені. Якщо Git є розповсюдженим SCM, важливо створити резервну копію всього локального сховища.
Йохан Буле

1 / Речення зі rsyncсторінки чоловіка, що цитується у цій відповіді, описує --cvs-excludeваріант, тому ви повинні використовувати його явно. 2 / Ви можете створювати .cvsignoreфайли в будь-якому каталозі, щоб ігнорувати конкретні проекти, вони також читаються. 3 / .gitвже ігнорується, коли ви користуєтесь --cvs-exclude, відповідно до посібника, тому його використання $HOME/.cvsignoreздається зайвим.
Niavlys

1

У мене було кілька дуже великих .gitignoreфайлів, і жодне з "чистих рісинсистентських" рішень не працювало на мене. Я написав цей скрипт для обгортки rsync , він повністю дотримується .gitignoreправил (включаючи !-style винятки та .gitignoreфайли у підкаталогах) і працює як шарм для мене.


Спробуйте це через locate -0e .gitignore | (while read -d '' x; do process_git_ignore "$x"; done), але виникає маса проблем. Файли в одному каталозі, які .gitignoreнеправильно відокремлені від імені каталогу /. Порожні рядки та коментарі неправильно трактуються. Душить про .gitignoreфайли в шляхах з пробілами (не майте на увазі фінди /opt/vagrant/embedded/gems/gems/rb-fsevent-0.9.4/spec/fixtures/custom 'path/.gitignoreз vagrantпакету для Ubuntu). Можливо, краще зробити як сценарій Perl.
Джессі Глік

@JesseGlick Я не впевнений, чому ви викликаєте функцію в сценарії. він призначений для використання в якості заміни rsync, що випадає , з певної причини, що обробка цитата / пробілу така біль. Якщо у вас є приклад gsyncкомандного рядка, який виходить з ладу, і .gitignoreпов'язаних з ним файлів, я був би радий уважніше ознайомитися.
cobbzilla

Мені потрібна rsyncціла файлова система з різними сховищами Git, розкиданими навколо неї. Можливо, ваш сценарій чудово працює у випадку синхронізації одного сховища.
Джессі Глік

1
однозначно так. вибачте, що я цього не прояснив. З цим скриптом, вам доведеться викликати його один раз за git repo, з каталогу repo.
cobbzilla

0

Перегляньте розділ ПРАВИЛА ФІЛЬТУ МЕРГ-ФАЙЛІВ у rsync (1).

Схоже, що можна створити правило rsync --filter, яке буде включати файли .gitignore у міру проходження структури каталогів.


0

Замість створення фільтрів виключення, ви можете git ls-filesвибрати для вибору кожного файлу rsync:

#!/usr/bin/env bash

if [[ ! $# -eq 2 ]] ; then
    echo "Usage: $(basename $0) <local source> <rsync destination>"
    exit 1
fi

cd $1
versioned=$(git ls-files --exclude-standard)
rsync --verbose --links --times --relative --protect-args ${versioned} $2

Це працює, навіть незважаючи на те, що git ls-filesповертає шляхи, розділені за новою лінією Можливо, не вийде, якщо ви переобладнали файли з пробілами у файлах файлів.


0

Альтернативи:

git ls-files -zi --exclude-standard |rsync -0 --exclude-from=- ...

git ls-files -zi --exclude-per-directory=".gitignore" |...

(rsync лише частково розуміє .gitignore)


0

Коротка відповідь

rsync -r --info=progress2 --filter=':- .gitignore' SOURCE DEST/

Значення параметрів:

-r: рекурсивна

--info=...: показати прогрес

--filter=...: виключити за правилами, переліченими у файлі .gitignore

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.