Запишіть операцію копіювання файлів за допомогою Git


141

Коли я переміщую файл у git за допомогою git-mv, статус показує, що файл було перейменовано, і навіть якщо я змінюю деякі частини, він все ще вважає майже те саме (що добре, тому що він дозволяє мені слідкувати за його історією) .

Коли я копіюю файл, оригінальний файл має деяку історію, яку я хотів би пов’язати з новою копією.

Я спробував перемістити файл, а потім намагався повторно здійснити покупку в оригінальному місці - коли переміщений git не дозволить мені перевірити початкове місце.

Я спробував зробити копію файлової системи, а потім додав файл - git перелічує його як новий файл.

Чи є якийсь спосіб зробити git запис операції копіювання файлу аналогічним чином, як він записує перейменування / переміщення файлу, де історія може бути відстежена до вихідного файлу?

Відповіді:


112

Git не здійснює відстеження перейменувань, ані відстеження копій, а це означає, що він не записує перейменування чи копії. Замість цього відбувається перейменування та виявлення копій . Ви можете попросити виявити перейменування в git diffgit show), скориставшись -Mопцією, ви можете запросити додаткове виявлення копії у змінених файлах, скориставшись -Cопцією ( -Cмається на увазі -M), а також можна попросити дорожче виявлення копії серед усіх файлів з --find-copies-harderабо -C -C(що означає -C, що означає -M). Див. Сторінку git-diff .

Ви можете також налаштувати мерзотник завжди робити перейменування виявлення, встановивши diff.renamesв логічне справжнє значення (наприклад , trueчи 1), і ви можете запросити мерзотник , щоб зробити виявлення копії теж, встановивши його copyабо copies. Див. Сторінку git-config .

Перевірте також -lпараметр до git diffта пов'язану змінну конфігурацій diff.renameLimit.


Зауважте, що git log <pathspec>в Git працює інакше: тут <pathspec>встановлено роздільники шляху, де шлях може бути назвою (під) каталогу. Він фільтрує та спрощує історію до того, як перейменувати та виявити копію, вступить у гру. Якщо ви хочете слідувати за перейменами та копіями, використовуйте git log --follow <filename>(що наразі трохи обмежено і працює лише для одного файлу).


1
@allyourcode: Що вас бентежить? Щоб увімкнути визначення копіювання за замовчуванням ви встановите diff.renamesна copies(наприклад , ' git config diff.renames copies«). Я погоджуюсь, що це трохи протикоректно.
Якуб Нарбський

Один розділ, який я, здається, не може розібрати, - це ", і ви можете попросити зробити за замовчуванням також перейменування виявлення". Ви хочете сказати, що є чотири значення, які можуть використовувати різні.імена (true, 1, copy, copy), і що всі вони роблять те саме?
allyourcode

1
@allyourcode: Вибачте, я цього не помічав. Виправлено зараз, дякую.
Якуб Нарубський

4
@ peschü: Git використовує об'єктну базу даних із вмістом як сховище репозиторію. Вміст файлу зберігається у вмісті "blob" під адресою, яка є хеш-вмістом SHA-1 (ну, тип + довжина + вміст). Це означає, що заданий вміст зберігається лише один раз. Nb. ця автоматична дедуплікація стала причиною створення системи резервного копіювання "bup", використовуючи формат git pack.
Якуб Нарбський

1
На відміну від рішення нижче, це не працює з відстеженням змін у діапазоні. Журнал Git дозволяє аргументувати діапазон ( git log -L123,456:file.xyz), який належним чином перейменовує перейменування, але не копіює, і ви не можете пройти - наступне в цьому випадку; Крім того, AFAICT, це не спрацьовує з виною в роботі.
Клімент

57

2020-05-19: Наступне рішення має переваги: ​​не змінювати журнал вихідного файлу, не створювати конфлікт злиття та бути коротшим.

Ви можете змусити Git виявити історію скопійованого файлу в трьох комітах:

  • Замість того, щоб копіювати, переключіться на нову гілку та перемістіть файл на його нове місце там.
  • Повторно додайте туди вихідний файл.
  • Об’єднайте нову гілку з початковою гілкою з опцією "не швидкий перехід" --no-ff.

(Кредити йдуть до Реймонда Чена .)


У попередньому рішенні було чотири коміти:

  • Замість того, щоб копіювати, переключіться на нову гілку та перемістіть файл на його нове місце там.
  • Перейдіть до оригінальної гілки та перейменуйте файл.
  • Об’єднайте нову гілку в оригінальну гілку, вирішивши тривіальний конфлікт, зберігаючи обидва файли.
  • Відновіть оригінальне ім'я файлу в окремому коміті.

(Рішення взято з https://stackoverflow.com/a/44036771/1389680 .)


7
Простота, стислість, 100% ... Ця відповідь - це державна послуга ..., яка підтримує все на виду
ptim

1
Яка різниця між moveі rename?
Вован

@vovan Ви маєте на увазі той факт, що в bash ви використовували б mvдля обох операцій? Я використовував "переміщення" для випадку, який може включати зміну каталогу файлу, і "перейменувати" для випадку, коли цього немає.
Роберт Поллак

2
Я спробував слідувати цьому (новому) рецепту, і це не вийшло. Це може допомогти, якщо ви показали фактичні команди.
Грег Ліндаль

1
@RobertPollak Я пробував різні версії цього, але вони не працювали. Під "переміщенням файлу" ви маєте на увазі git mv orig new? Під "читайте оригінал", ви маєте на увазі cp new orig && git add orig?
ᆼ ᆺ ᆼ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.