Я использую git для нового проекта, который имеет две параллельные - но в настоящее время экспериментальные - ветки разработки:
master
: импорт существующей кодовой базы плюс несколько модов, в которых я обычно уверенexp1
: экспериментальный филиал № 1exp2
: экспериментальный филиал № 2
exp1
и exp2
представляют два очень разных архитектурных подхода. Пока я не продвинусь дальше, у меня нет никакого способа узнать, какой из них (если любой) будет работать. Поскольку я делаю успехи в одной ветви, у меня иногда есть изменения, которые были бы полезны в другой ветви и хотели бы объединить только те.
Каков наилучший способ объединить выборочные изменения из одной ветви разработки в другую, оставляя позади все остальное?
Подходы, которые я рассмотрел:
git merge --no-commit
с последующей ручной постановкой большого количества правок, которые я не хочу делать общими для ветвей.Ручное копирование общих файлов во временный каталог с последующим
git checkout
перемещением в другую ветвь, а затем более ручное копирование из временного каталога в рабочее дерево.Разновидность вышеупомянутого. Оставьте
exp
сейчас ветки и используйте два дополнительных локальных репозитория для экспериментов. Это делает ручное копирование файлов намного проще.
Все три из этих подходов кажутся утомительными и подверженными ошибкам. Я надеюсь, что есть лучший подход; что-то похожее на параметр пути фильтра, что сделало бы git-merge
более селективным.
источник
git merge -s ours --no-commit
сопровождаемая некоторыми, неgit read-tree
будет хорошим решением для этого? См. Stackoverflow.com/questions/1214906/…Ответы:
Вы используете команду cherry-pick, чтобы получить отдельные коммиты из одной ветви.
Если нужного вам изменения нет в отдельных фиксациях, то используйте метод, показанный здесь, чтобы разделить фиксацию на отдельные фиксации . Грубо говоря, вы используете
git rebase -i
для редактирования исходной фиксации, затемgit reset HEAD^
для выборочного возврата изменений, а затемgit commit
для фиксации этого бита в качестве новой фиксации в истории.Здесь, в журнале Red Hat, есть еще один приятный метод, в котором они используют
git add --patch
или, возможно,git add --interactive
который позволяет вам добавлять только части фрагмента, если вы хотите разделить различные изменения в отдельном файле (найдите на этой странице «split»).Разделив изменения, теперь вы можете выбрать те, которые хотите.
источник
У меня была точно такая же проблема, как вы упомянули выше. Но я нашел это более ясным в объяснении ответа.
Резюме:
Извлечь путь (и) из ветви, которую вы хотите объединить,
Подсказка: это также работает так,
--
как не видно в связанном посте.или выборочно объединить куски
В качестве альтернативы используйте сброс, а затем добавьте с параметром
-p
,Наконец совершить
источник
foo.c
сделать ,git reset HEAD foo.c
чтобы убрать из буфера , что файл , а затем вы можете дифф его. Я узнал об этом после того, как попробовал и вернулся сюда, чтобы найти ответ на этот вопросgit diff --cached
git checkout -p <revision> -- <path>
будет то же, что и выдача первых трех команд, которые вы описали :)Чтобы выборочно объединить файлы из одной ветви в другую, запустите
где
branchX
ветка, из которой вы хотите объединиться с текущей веткой?--no-commit
Опция этапа файлов , которые были объединены с помощью Git фактически не совершать их. Это даст вам возможность модифицировать объединенные файлы так, как вы хотите, а затем зафиксировать их самостоятельно.В зависимости от того, как вы хотите объединить файлы, есть четыре случая:
1) Вы хотите истинное слияние.
В этом случае вы принимаете объединенные файлы так, как Git автоматически объединяет их, а затем фиксируете их.
2) Есть файлы, которые вы не хотите объединять.
Например, вы хотите сохранить версию в текущей ветви и игнорировать версию в ветви, из которой вы объединяете.
Чтобы выбрать версию в текущей ветке, запустите:
Это восстановит версию
file1
в текущей ветке и перезапишетfile1
Git, автоматически объединенную с версией.3) Если вы хотите версию в BranchX (а не истинное слияние).
Запустить:
Это позволит получить версию
file1
inbranchX
и перезаписатьfile1
автоматически слитой Git.4) Последний случай, если вы хотите выбрать только конкретные слияния в
file1
.В этом случае вы можете отредактировать измененное
file1
напрямую, обновить его до того, каким вы хотите, чтобы версияfile1
стала, а затем зафиксировать.Если Git не может объединить файл автоматически, он сообщит о файле как о «без объединения » и создаст копию, где вам нужно будет разрешить конфликты вручную.
Для дальнейшего объяснения на примере, скажем, вы хотите объединиться
branchX
с текущей веткой:Затем вы запускаете
git status
команду для просмотра статуса измененных файлов.Например:
Где
file1
,file2
иfile3
те файлы , мерзавец , успешно автоматически объединены.Это означает, что изменения в
master
иbranchX
для всех этих трех файлов были объединены без каких-либо конфликтов.Вы можете проверить, как было выполнено слияние, запустив
git diff --cached
;Если вы обнаружите, что слияние нежелательно, вы можете
git commit
Если вы не хотите объединяться
file1
и хотите сохранить версию в текущей веткеЗапустить
Если вы не хотите объединять
file2
и хотите только версию вbranchX
Запустить
Если вы хотите
file3
объединиться автоматически, ничего не делайте.Git уже слил это на данный момент.
file4
выше - неудачное слияние Git. Это означает, что изменения в обеих ветвях происходят в одной строке. Здесь вам нужно будет разрешить конфликты вручную. Вы можете отказаться от слияния, сделанного, отредактировав файл напрямую или выполнив команду извлечения для версии в ветви, которой вы хотитеfile4
стать.Наконец, не забудьте
git commit
.источник
git merge --no-commit branchX
это просто перемотка вперед, указатель будет обновлен, и --no-commit, таким образом, будет игнорироваться--no-ff
чтобы предотвратить такое поведение?Мне не нравятся вышеуказанные подходы. Использование cherry-pick отлично подходит для выбора одного изменения, но это неприятно, если вы хотите внести все изменения, кроме некоторых плохих. Вот мой подход.
Нет
--interactive
аргумента, который вы можете передать git merge.Вот альтернатива:
У вас есть некоторые изменения в ветке 'feature', и вы хотите, чтобы некоторые, но не все, перешли к 'master' не небрежным образом (т.е. вы не хотите выбирать и фиксировать каждую из них)
Так что просто оберните это в сценарии оболочки, измените master на $ to и измените функцию на $ from, и все готово:
источник
git rebase -i $to
егоgit rebase -i $to || $SHELL
, чтобы пользователь мог звонить иgit --skip
т. Д., Если это необходимо, если перебазировка не удалась. Также стоит объединять в цепочки строки&&
вместо новых.Есть еще один путь:
Это смесь между
git checkout
иgit add -p
может быть именно тем, что вы ищете:источник
Хотя некоторые из этих ответов довольно хороши, мне кажется, что никто не ответил на первоначальное ограничение OP: выбор определенных файлов из определенных веток. Это решение делает это, но может быть утомительным, если есть много файлов.
Допустим , у вас есть
master
,exp1
иexp2
ветви. Вы хотите объединить один файл из каждой экспериментальной ветви в мастер. Я бы сделал что-то вроде этого:Это даст вам различия в файлах для каждого файла, который вы хотите. Ничего больше. Не меньше. Полезно, чтобы у вас были радикально отличающиеся изменения файлов между версиями - в моем случае, изменение приложения с Rails 2 на Rails 3.
РЕДАКТИРОВАТЬ : это объединит файлы, но делает умное объединение. Я не смог выяснить, как использовать этот метод для получения информации о различиях в файле (возможно, это все равно будет для экстремальных различий. Раздражающие мелочи, такие как пробелы, объединяются, если вы не используете
-s recursive -X ignore-all-space
опцию)источник
git checkout exp1 path/to/file_a path/to/file_x
git checkout feature <path>/*
чтобы получить группы файлов.1800 ИНФОРМАЦИЯ ответ полностью правильный. Однако, как git noob, «использовать git cherry-pick» было недостаточно для того, чтобы я понял это без каких-либо дополнительных копаний в Интернете, поэтому я решил опубликовать более подробное руководство на случай, если кто-то еще будет в похожая лодка.
Мой вариант использования - выборочное извлечение изменений из чьей-либо ветки github в мою. Если у вас уже есть локальный филиал с изменениями, вам нужно только выполнить шаги 2 и 5-7.
Создайте (если не создали) локальную ветвь с изменениями, которые вы хотите внести.
$ git branch mybranch <base branch>
Переключитесь на это.
$ git checkout mybranch
Внесите необходимые изменения из учетной записи другого человека. Если вы этого еще не сделали, вы захотите добавить их в качестве удаленного.
$ git remote add repos-w-changes <git url>
Сноси все с их ветки.
$ git pull repos-w-changes branch-i-want
Просмотрите журналы фиксации, чтобы увидеть, какие изменения вы хотите:
$ git log
Вернитесь к ветке, в которую хотите внести изменения.
$ git checkout originalbranch
Черри выбирает ваши коммиты, один за другим, с помощью хешей.
$ git cherry-pick -x hash-of-commit
Наконечник шляпы: http://www.sourcemage.org/Git_Guide
источник
git cherry
команду (сначала обратитесь к руководству), чтобы определить коммиты, которые вы еще не объединили.Вот как вы можете заменить
Myclass.java
файл вmaster
ветке наMyclass.java
вfeature1
ветке. Это будет работать, даже еслиMyclass.java
не существуетmaster
.Обратите внимание, что это перезапишет, а не объединит, и скорее проигнорирует локальные изменения в основной ветке.
источник
theirs
перезаписатьours
=> +1 Cheers;)2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
Простой способ - объединить конкретные файлы из двух веток, а не просто заменить конкретные файлы файлами из другой ветки.
Шаг первый: разветвить ветви
git diff branch_b > my_patch_file.patch
Создает файл патча разницы между текущей веткой и branch_b
Шаг второй: примените патч к файлам, соответствующим шаблону
git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch
полезные заметки по опциям
Вы можете использовать
*
в качестве шаблона в шаблоне включения.Косые черты не нужно избегать.
Кроме того, вместо этого вы можете использовать --exclude и применять его ко всем, кроме файлов, соответствующих шаблону, или отменить патч с помощью -R
Параметр -p1 является удержанием команды * unix patch и тот факт, что содержимое файла исправления предшествует каждому имени файла с помощью
a/
илиb/
(или более в зависимости от того, как был создан файл исправления), которое необходимо удалить, чтобы оно могло выяснить реальный файл с путем к файлу, к которому должен быть применен патч.Зайдите на страницу man для git-apply, чтобы узнать больше вариантов.
Шаг третий: нет третьего шага
Очевидно, что вы захотите зафиксировать свои изменения, но кто скажет, что у вас нет других связанных твиков, которые вы хотели бы сделать, прежде чем сделать свой коммит.
источник
Вот как вы можете заставить историю следовать только паре файлов из другой ветки с минимальными усилиями, даже если более «простое» объединение принесло бы гораздо больше изменений, которые вам не нужны.
Во-первых, вы сделаете необычный шаг, предварительно объявив, что вы собираетесь зафиксировать слияние, без мерзавца, который вообще ничего не делает с файлами в вашем рабочем каталоге:
, , , где "branchname" - это то, из чего вы утверждаете, что объединяетесь. Если вы сделаете коммит сразу, он не внесет никаких изменений, но он все равно покажет родословную из другой ветви. Вы можете добавить больше веток / тегов / и т.д. в командной строке, если вам нужно, а также. На данный момент, однако, нет изменений для фиксации, поэтому получите файлы из других ревизий, затем.
Если вы объединяли несколько ветвей, повторите при необходимости.
Теперь файлы из другой ветки находятся в индексе, готовые к фиксации, с историей.
и у вас будет много объяснений, которые нужно сделать в этом сообщении коммита.
Пожалуйста, обратите внимание, на случай, если неясно, что это неправильно. Это не в духе того, для чего нужна "ветка", и "вишня" - это более честный способ сделать то, что вы будете делать здесь. Если вы захотите сделать еще одно «слияние» для других файлов в той же ветке, которую вы не перенесли в прошлый раз, это остановит вас сообщением «уже в курсе». Это признак отсутствия ветвления, когда у нас должно быть, в ветке «from» должно быть несколько разных ветвей.
источник
git merge --no-ff --no-commit -s outs branchname1
) - это именно то, что я искал! Спасибо!Я знаю, что немного опоздал, но это мой рабочий процесс для объединения отдельных файлов.
источник
Самый простой способ - установить репо в ту ветку, с которой вы хотите объединиться, и затем запустить,
Если вы бежите
вы увидите файл уже в постановке ...
Тогда беги
Просто.
источник
Я нашел этот пост, чтобы содержать самый простой ответ. Просто сделайте:
Пример:
Смотрите пост для получения дополнительной информации.
источник
Странно, что у git до сих пор нет такого удобного инструмента «из коробки». Я интенсивно использую его, когда обновляю ветку старой версии (в которой все еще много пользователей программного обеспечения), просто исправляя некоторые ошибки из ветки текущей версии. В этом случае часто требуется быстро получить только несколько строк кода из файла в стволе, игнорируя множество других изменений (которые не должны входить в старую версию) ... И, конечно, интерактивное трехстороннее объединение требуется в этом случае,
git checkout --patch <branch> <file path>
не может использоваться для этой цели выборочного слияния.Вы можете сделать это легко:
Просто добавьте эту строку в
[alias]
раздел в вашем глобальном.gitconfig
или локальном.git/config
файле:Это означает, что вы используете Beyond Compare. Просто измените программное обеспечение на ваш выбор, если это необходимо. Или вы можете изменить его на трехстороннее автоматическое слияние, если вам не нужно интерактивное выборочное слияние:
Тогда используйте как это:
Это даст вам истинную выборочную возможность слияния в виде дерева любого файла в другой ветке.
источник
Это не совсем то, что вы искали, но это было полезно для меня:
Это смесь некоторых ответов.
источник
git checkout HEAD file1
чтобы сохранить текущую версию и удалить файлfile1
, можно использовать-p
опцию, чтобы выбрать часть файла для объединения. спасибо за трюк!Я бы сделал
Таким образом, вы можете ограничить диапазон коммитов для файлового шаблона из ветки.
Похищен у: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
источник
У меня была точно такая же проблема, как вы упомянули выше. Но я нашел этот блог Git более четким в объяснении ответа.
Команда по вышеуказанной ссылке:
источник
Мне нравится ответ 'git-interactive-merge' выше, но есть один более простой. Позвольте git сделать это для вас, используя интерактивную комбинацию ребаз и на:
Так что дело в том, что вы хотите C1 и C2 из ответвления «Feature» (точка ветвления «A»), но пока ничего из остального.
Который, как указано выше, перенаправляет вас в интерактивный редактор, где вы выбираете строки «выбора» для C1 и C2 (как указано выше). Сохраните и выйдите, а затем он продолжит ребазирование и даст вам ветку temp, а также HEAD на master + C1 + C2:
Затем вы можете просто обновить master до HEAD и удалить временную ветку, и все готово:
источник
Как насчет
git reset --soft branch
? Я удивлен, что никто еще не упомянул об этом.Для меня это самый простой способ выборочно выбрать изменения из другой ветки, так как эта команда помещает в мое рабочее дерево все изменения различий, и я могу легко выбрать или вернуть то, что мне нужно. Таким образом, я имею полный контроль над зафиксированными файлами.
источник
Я знаю, что этот вопрос старый и есть много других ответов, но я написал свой собственный скрипт под названием «pmerge», чтобы частично объединить каталоги. Эта работа еще не завершена, и я все еще изучаю скрипты git и bash.
Эта команда использует,
git merge --no-commit
а затем отменяет изменения, которые не соответствуют указанному пути.Использование:
git pmerge branch path
Пример:
git merge develop src/
Я не проверял это экстенсивно. В рабочем каталоге не должно быть никаких незафиксированных изменений и неотслеживаемых файлов.
источник
Вы можете использовать
read-tree
для чтения или объединения данного удаленного дерева в текущий индекс, например:Чтобы выполнить слияние, используйте
-m
вместо этого.Смотрите также: Как мне объединить подкаталог в git?
источник
Простой подход для выборочного слияния / фиксации по файлу:
git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes
источник
Если у вас не так много файлов, которые были изменены, это оставит вас без дополнительных фиксаций.
1. Дублирующая ветка временно
$ git checkout -b temp_branch
2. Сброс до последнего требуемого коммита
$ git reset --hard HEAD~n
, гдеn
указано количество коммитов , которое вам нужно вернуть3. Оформите каждый файл из оригинальной ветки
$ git checkout origin/original_branch filename.ext
Теперь вы можете зафиксировать и принудительно нажать (чтобы перезаписать удаленный), если это необходимо.
источник
Если вам нужно только объединить конкретный каталог и оставить все остальное без изменений, но при этом сохранить историю, вы можете попробовать это ... создать новый
target-branch
вариантmaster
перед экспериментом.Следующие шаги предполагают, что у вас есть две ветви
target-branch
иsource-branch
, и каталог,dir-to-merge
который вы хотите объединить, находится вsource-branch
. Также предположим, что у вас есть другие каталоги, такие какdir-to-retain
в цели, которые вы не хотите изменять и сохранять историю. Кроме того, предполагается, что есть конфликты слияния вdir-to-merge
.источник
Когда между текущими коммитами двух ветвей изменилось всего несколько файлов, я вручную объединяю изменения, просматривая разные файлы.
git difftoll <branch-1>..<branch-2>
источник