Mercurial: объединение одного файла между ветками в одно репо

Когда у меня есть две ветки в репозитории Hg, как объединить только один файл с другой веткой без объединения всех остальных файлов из набора изменений?

Можно ли объединить только определенные файлы вместо всего набора изменений?


person Jox    schedule 03.07.2009    source источник


Ответы (4)


ВНИМАНИЕ: такое фиктивное слияние, которое рекомендовано @Martin_Geisler, действительно может вас испортить, если позже вы захотите сделать истинное слияние двух ветвей. Будет записано фиктивное слияние, в котором будет указано, что вы выполняете слияние в ветку, в которую выполнялось фиктивное слияние - вы не увидите изменений. Или, если вы объединитесь с другой веткой, изменения в этой другой ветке будут отменены.

Если все, что вам нужно, это скопировать весь файл из одной ветки в другую, вы можете просто сделать:

   hg update -r to-branch
   hg revert -r from-branch file
   hg ci -m 'copied single file from from-branch to to-branch

Если вы хотите выбрать разные части этого файла, тогда "hg record" будет полезно.

Я только что сделал это в своем домашнем каталоге .hgignore.

Если обе ветки внесли изменения в файл, который вы хотите сохранить, грязный трюк будет заключаться в том, чтобы создать слияние двух веток с помощью hg merge, возможно / возможно, в еще одной ветке, проверить это, а затем скопировать один файл между слиянием и переходом:

   hg update -r to-branch
   branch merge-branch
   hg merge -r from-branch
   hg ci -m 'temp merge to be discarded"
   hg update -r to-branch
   hg revert -r merge-branch single-file
   hg ci -m 'merged single-file from from-branch to to-branch"
   hg strip merge-branch

Стоит упомянуть: способ копирования одного файла между ветвями (или ревизиями, или от ревизии к слиянию, или ....) - это hg revert. Т.е.

   hg update -r Where-you-want-to-copy-to
   hg revert -r Where-you-want-to-copy-from file-you-want-to-copy
   ...
   hg ci

По некоторым причинам меня и некоторых моих коллег это ОЧЕНЬ смущает. revert == copy ... имеет смысл для некоторых шаблонов использования, но не для всех.

person Krazy Glew    schedule 26.10.2012
comment
Это должен быть принятый ответ вместо того, что дал Мартин Гейслер. Хотя на самом деле он не будет объединять файл, его копирование - это то, что нужно делать большую часть времени, и это не испортит ветку. - person noamik; 08.08.2013
comment
Это отлично сработало для переноса одного файла из ветки в магистраль. Однако я заметил одну вещь: регистрация в стволе не отображается в истории файла, что прискорбно. - person Brad Oestreicher; 23.09.2013
comment
привет и спасибо за ответ. Однако у меня возникли проблемы, в моей ситуации моя исходная ветка содержит файл, которого нет в моей ветке по умолчанию, но я хочу скопировать его обратно, не объединяя остальную часть ветки. Когда я пытаюсь сделать то, что вы описали, я получаю «нет такого файла в версии». Есть предложения? - person propagated; 06.02.2014
comment
Таким образом, обходной путь для моей проблемы - скопировать файлы вручную, а затем запустить команды копирования, но мне интересно, есть ли решение для новых файлов, которых нет в целевой ветке? - person propagated; 06.02.2014
comment
@propagated: ветка №1 и №2. В ветке №2 вы создали файл Foo. Чтобы распространить Foo на ветку №1. Если добавление файла Foo было единственным изменением, вы выполняете слияние. Но если в ветке № 2 есть другие вещи, которые вы не хотите объединять в настоящее время и которые вы не хотите, чтобы слияние всего репо неправильно запомнилось, то есть если вы просто хотите скопировать файл (или файлы) из ветки № 2 в ветку №1, затем выполните: hg update -r Branch # 1; hg revert -r Branch # 2 Foo; hg ci. Самая большая проблема в том, что завершение имени файла не работает, поскольку файл Foo еще не существует в ветке №1. - person Krazy Glew; 06.04.2014
comment
@Brad_Oestreicher: да, жаль, что в истории Mercurial нет никаких указаний на то, что произошло, кроме любого комментария, который вы предоставили. Например. Я полагаюсь на hg glog в получении хороших древовидных диаграмм. Было бы неплохо, если бы можно было провести черту между ревизиями, между которыми копируется файл. Т.е. было бы неплохо отслеживать как частичные, так и полные слияния. Слишком много DVCS имеют точку зрения только на весь репозиторий. - person Krazy Glew; 06.04.2014
comment
@KrazyGlew, чего нет в DVCS? - person n611x007; 07.07.2016
comment
Есть ли способ переименовать скопированный файл за один раз? С hg revert, я думаю, это может быть только hg mv-ed после hg commit (для возврата). Итак, это два коммита. - person n611x007; 07.07.2016
comment
@ n611x007 В: Есть ли способ переименовать скопированный файл за один раз? О: Не знаю - я сейчас не использую Mercurial. Но даже если нет: зачем это нужно? Запустите (под) ветвь, скопируйте файл, переименуйте его и затем слейте обратно в родительскую ветвь = ›только один шаг в родительской ветке, хотя на самом деле их несколько. Не совсем так красиво, но общий подход. - person Krazy Glew; 13.07.2016
comment
@ n611x007 В: какой DVCS [имеет общую точку зрения на репо]? A1: Я не знаю ни одного текущего DVCS, который не был бы полным репо (за исключением различного импорта, который является болезненным). A2: CVS не является DVCS, но поддерживает частичные проверки и проверки. A3: Мой cvs-file-merge превратил CVS в DVCS, но я прекратил работу над этим, когда Линус объявил о git. A4: Линус сказал мне, что базовая структура git может поддерживать частичную co / ci и другие вещи subrepo, но это будет большим изменением для некоторого фарфора. - person Krazy Glew; 13.07.2016
comment
В результате файл снова добавлен в репозиторий? Так будет ли он потреблять вдвое больше места после такой операции? Или Hg сумеет увидеть, что файл уже в репо? - person texnic; 06.10.2018

Неа. Mercurial работает на основе набора изменений.

Но вы можете выполнить "фиктивное слияние "где вы игнорируете входящие изменения из одной из веток. Перед тем, как сделать коммит, вы можете вернуть выбранные файлы в любое желаемое состояние:

% HGMERGE=internal:local hg merge     # keep my files
% hg revert --rev other-branch a.txt  # update a.txt to other branch
% hg commit -m 'Dummy merge to pick a.txt from other-branch.'

Может быть, это вам немного поможет.

person Martin Geisler    schedule 03.07.2009
comment
ВНИМАНИЕ: такое фиктивное слияние может действительно вас испортить, если позже вы захотите выполнить настоящее слияние двух веток. Будет записано фиктивное слияние, в котором будет указано, что вы выполняете слияние в ветку, в которую выполнялось фиктивное слияние - вы не увидите изменений. Или, если вы объединитесь с другой веткой, изменения в этой другой ветке будут отменены. // Если все, что вам нужно, это скопировать весь файл из одной ветки в другую, вы можете просто hg update -r to-branch; hg revert -r file // если вы хотите выбрать разные части этого файла, то вам пригодится запись hg. // Я только что сделал это в моем домашнем каталоге .hgignore. - person Krazy Glew; 26.10.2012
comment
Грязный трюк состоит в том, чтобы создать слияние двух веток с помощью hg merge, проверить это, а затем скопировать один файл между слиянием и ветвью to с помощью hg update -t ​​to-branch; ветка слияние-ветка; hg merge -r из-ветки; hg ci -m 'temp merge следует отбросить; hg update -r to-branch; hg revert -r слияние-ветвь один-файл-и-хочу; hg ci -m 'объединяет один файл из ветки в ветку; hg strip слияние-ветвь. - person Krazy Glew; 26.10.2012
comment
О, черт возьми, с таким же успехом я мог бы превратить свои комментарии в настоящий ответ. - person Krazy Glew; 26.10.2012

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

hg update -r branch-merging-to
hg extdiff -p vimdiff -r branch-merging-from file-I-am-merging

Для этого вам нужно включить внешние инструменты в вашем .hgrc, что означает просто добавить эти строки:

[extensions]
hgext.extdiff =  
person Toby Searle    schedule 20.03.2015

Один довольно простой способ получить желаемый результат - это сделать это в два этапа: сначала использовать graft, затем использовать histedit.

Скажем, это отправная точка, и вам нужно выбрать некоторые части C и D для объединения после E:

A---B---C---D
      \
       -E

Затем вы должны пересадить C и D поверх E:

A---B---C---D
      \
       -E--C'--D'

Затем используйте hg histedit для редактирования C' и D'. Во время редактирования вы можете внести любые изменения, которые захотите, но в этом случае вы просто вернете все ненужные файлы (или даже их части).

(Обратите внимание, что histedit edit работает путем временного обновления вашей рабочей папки для соответствия содержимому данного набора изменений, как если бы он еще не был зафиксирован. Таким образом, вы можете легко вернуть ненужные файлы, а затем hg histedit --continue, что фактически заменит отредактированный набор изменений.)

Итак, окончательный результат будет:

A---B---C---D
      \
       -E--C''--D''

Где '' ревизии были изменены по мере необходимости.

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

person StayOnTarget    schedule 10.06.2021