Я использую git в новом проекте, который имеет две параллельные - но в настоящее время экспериментальные - ветви разработки:
master
: импорт существующей кодовой базы плюс несколько модификаций, в которых я в целом уверен.exp1
: экспериментальная ветка #1exp2
: экспериментальная ветвь #2exp1
и exp2
представляют собой два очень разных архитектурных подхода. Пока я не продвинусь дальше, я не могу знать, какой из них (если вообще какой-либо) будет работать. По мере продвижения в одной ветке у меня иногда появляются правки, которые были бы полезны в другой ветке, и я хотел бы объединить именно их.
**Какой лучший способ объединить выборочные изменения из одной ветки разработки в другую, оставив при этом все остальное?
Подходы, которые я рассматривал:
git merge --no-commit
с последующим ручным удалением большого количества правок, которые я не хочу делать общими между ветками.
Ручное копирование общих файлов во временный каталог с последующим git checkout
для перемещения в другую ветвь, а затем еще более ручное копирование из временного каталога в рабочее дерево.
Вариант вышеописанного. Откажитесь пока от веток exp
и используйте два дополнительных локальных репозитория для экспериментов. Это сделает ручное копирование файлов гораздо более простым.
Все эти три подхода кажутся утомительными и подверженными ошибкам. Я надеюсь, что есть лучший подход; что-то сродни параметру пути фильтра, который сделает git-merge
более избирательным.
У меня была точно такая же проблема как и упоминаемый вами выше. Но я нашел это яснее объяснить ответ.
Резюме:
$ Git в кассе имя_ветки -- <пути>...
Подсказка: он также работает без --
как видно, в связанном пост.
$ Git в кассе -п имя_ветки -- <пути>...
Кроме того, используйте сброс, а затем добавить с опцией -п
,
ЖКТ $ сброса <пути>... $ в Git добавить -Р <дорожки>...
$ коммит в git'е -м " с'слияние' эти изменения"в
Вы используете команду cherry-pick, чтобы получить отдельные коммиты из одной ветки.
Если нужное вам изменение(я) не находится в отдельных коммитах, то используйте метод, показанный здесь, чтобы разделить коммит на отдельные коммиты. Грубо говоря, вы используете git rebase -i
для получения исходного коммита для редактирования, затем git reset HEAD^
для выборочного возврата изменений, а затем git commit
для фиксации этого фрагмента как нового коммита в истории.
Есть еще один хороший метод здесь в Red Hat Magazine, где используется git add --patch
или, возможно, git add --interactive
, который позволяет добавлять только части hunk, если вы хотите разделить различные изменения на отдельные файлы (поиск на этой странице по "split").
Разделив изменения, вы теперь можете выбрать только те, которые вам нужны.
Выборочно объединить файлы из одного филиала в другой филиал, запустить
git merge --no-ff --no-commit branchX
где branchX` является филиалом которой вы хотите объединить в текущей ветви.
В `--без фиксации опции есть файлы, которые были объединены с помощью Git без фиксации их. Это даст вам возможность изменить объединенный файл, однако, вы хотите и затем совершают их сами.
В зависимости от того, как вы хотите объединить файлы, есть четыре случая:
В данном случае, вы принимаете объединенные файлы как мерзавец слил их автоматически, а затем фиксировать их.
Например, вы хотите сохранить версию в текущую ветку и игнорировать версия в ветке слиянии от.
Выберите вариант в текущей ветке, выполните:
git checkout HEAD file1
Это позволит получить версию "файл1" в текущей ветке и перезаписать файл file1 automerged с помощью Git.
Выполнить:
git checkout branchX file1
Это позволит получить версию файл1
в branchX
и заменить файл1
авто-объединены с помощью Git.
В этом случае, вы можете изменить измененный файл file1 напрямую, обновить его до все, что вы'хочу, чтобы версия "файл1", чтобы стать, а потом совершить.
Если Git не может автоматически слить файла, он сообщит файл как "unmerged" и скопировать, где вам придется разрешать конфликты вручную.
<БР/>
Далее объясню на примере, пусть'говорят, что вы хотите, чтобы объединить branchX
в текущей ветке:
git merge --no-ff --no-commit branchX
Затем вы выполните команду статус ГИТ
для просмотра состояния измененные файлы.
Например:
git status
# On branch master
# Changes to be committed:
#
# modified: file1
# modified: file2
# modified: file3
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: file4
#
Где файл1
, файл2
, и файл file3
являются файлами git успешно авто-слили.
Что это означает, что изменения в master
и `branchX за все эти три дела были объединены вместе, без всяких конфликтов.
Вы можете проверить, как слияние осуществляется путем запуска ГИТ дифф --кэшированные
;
git diff --cached file1
git diff --cached file2
git diff --cached file3
коммитов
Запустить
git checkout HEAD file1
branchX
Запустить
git checkout branchX file2
ГИТ уже слили его в этот момент.
<БР/>
файл file4
выше не удалось объединить с помощью Git. Это означает, что есть изменения в обеих ветвях, которые происходят на одной и той же линии. Это где вы должны разрешать конфликты вручную. Вы можете отбросить слили сделано путем редактирования файла напрямую или выполнив команду проверки для версия в ветке хочешь файл file4 стать.
<БР/>
Наконец, Дон'т забыть коммитов
.
Мне не нравятся описанные выше подходы. Использование cherry-pick отлично подходит для выбора одного изменения, но это боль, если вы хотите внести все изменения, кроме некоторых плохих. Вот мой подход.
Не существует аргумента --interactive
, который можно передать git merge.
Вот альтернатива:
У вас есть некоторые изменения в ветке 'feature', и вы хотите перенести некоторые, но не все из них в 'master' небрежным способом (т.е. вы не хотите выбирать и коммитить каждую из них).
git checkout feature
git checkout -b temp
git rebase -i master
# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change
# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
git checkout master
git pull . temp
git branch -d temp
Так что просто оберните это в сценарий оболочки, измените master на $to и измените feature на $from, и все готово:
#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp
Есть еще один способ не пойти:
git checkout -p
Это смесь между Git в кассе
и в Git добавить -P
и вполне может быть именно то, что вы ищете:
-p, --patch
Interactively select hunks in the difference between the <tree-ish>
(or the index, if unspecified) and the working tree. The chosen
hunks are then applied in reverse to the working tree (and if a
<tree-ish> was specified, the index).
This means that you can use git checkout -p to selectively discard
edits from your current working tree. See the “Interactive Mode”
section of git-add(1) to learn how to operate the --patch mode.
Хотя некоторые из этих ответов являются очень хорошо, я чувствую, что ничего на самом деле ответил ОП'ы оригинальный ограничение: при выборе определенных файлов из конкретных отраслей. Это решение делает это, но может быть утомительно, если есть много файлов.
Допустим, у вас есть мастер
, `выр1 и выр2 филиалов. Вы хотите объединить один файл из каждой из экспериментальных веток в мастер. Я хотел сделать что-то вроде этого:
git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b
# save these files as a stash
git stash
# merge stash with master
git merge stash
Это даст вам в файл различий для каждого из файлов, которые вы хотите. Ничего больше. Ничего не менее. Это's полезный у вас кардинально разные изменения файлов между версиями-в моем случае, меняется приложение с рельсов 2 на рельсы 3.
Редактировать: это позволит объединить файлы, но не идеальным слиянием. Я не'т в состоянии выяснить, как использовать этот метод, чтобы получить файл различий информации (может быть, это все равно на большую разницу. Раздражающие мелочи, как пробелы сливаются обратно в, если вы используете-с рекурсивным -х игнорировать-все опции)
1800 INFORMATION'ответ полностью правильный. Однако мне, как новичку в git, "use 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
Вот как вы можете заменить файл Myclass.javaв
мастерфилиал
Myclass.java " в " функция1филиал. Он будет работать даже если Myclass.java
не'т существуют на мастер
.
git checkout master
git checkout feature1 Myclass.java
Обратите внимание, это приведет к перезаписи - не слить - и игнорировать локальные изменения в ветке master, а.
Самый простой способ, на самом деле слияние отдельные файлы из двух ветвей, а не просто заменить определенные файлы с единицами из другой ветки.
ГИТ дифф branch_b > my_patch_file.патч
Создает файл патч разницы между текущей ветви и branch_b
в Git применить -Р1 --включить=шаблон/соответствия/этот/путь/к/файлу/или/папке my_patch_file.патч
Вы можете использовать *
в качестве шаблона в шаблон.
Слеши Дон'т должны быть экранированы.
Кроме того, вы можете использовать, вместо того, чтобы исключить и применить его ко всему, кроме файлы, соответствующие этому шаблону, или обратный патч с -Р
В -Р1 параметр остался от *в Unix патч команду и тот факт, что патч файл'ы содержание начало каждого файла с /
или B/
( или более в зависимости от того как патч файл был создан), который нужно зачистить, так что он может выяснить настоящие файла, путь к файлу патч должен быть применен.
Проверьте Man-страницу для Git-применять дополнительные опции.
Очевидно, что вы'хочу, чтобы зафиксировать изменения, но кто's, чтобы сказать, что вы Дон'Т есть какие-то другие связанные настройки, которые вы хотите сделать прежде чем совершить.
Здесь's, как вы можете узнать историю всего пару файлов из другой ветки с минимумом суеты, даже если более "простой" и слиться бы принес много изменений, что вы Дон'т хотите.
Во-первых, вы'll принимать необычный шаг, объявив заранее, что то, что вы'ре собирается совершить-это слияния, Git не делать что-либо вообще файлы в вашем рабочем каталоге:
git merge --no-ff --no-commit -s ours branchname1
. . . куда "branchname" это все, что вы утверждаете, сливаясь с. Если бы Вы были принять решение прямо сейчас, то не будет никакого изменения, но было бы все-таки показать родословную от другой ветви. Вы можете добавить больше веток/теги/и т. д. в командную строку если вам нужно, как хорошо. Хотя на данный момент, никаких изменений совершить, чтобы получить файлы из других изменений, далее.
git checkout branchname1 -- file1 file2 etc
Если вы сливались с более чем одной другой ветке, повторять по мере необходимости.
git checkout branchname2 -- file3 file4 etc
Теперь файлы из другой ветви в индексе, готовы быть преданными, с историей.
git commit
и вы'придется многое объяснить в том, что совершить сообщение.
Обратите внимание хотя, в случае, если это было'т ясно, что это перепутались, что нужно сделать. Это не в духе какая-то "филиал" это для, и выбирают более честный путь, чтобы делать то, что вы'd было делать, вот. Если вы хотели сделать еще один "слияние" и другие файлы на этой же ветке, что вы ничего'т принести за последнее время, он перестанет вас с собой "уже в курсе, что" сообщение. Это'ы симптомом не ветвящиеся, когда мы должны были, в "от" ветки должен быть больше, чем один другой ветке.
Я нашел этот пост, чтобы содержать самый простой ответ. Просто сделать:
$ #git checkout <branch from which you want files> <file paths>
Пример:
$ #pulling .gitignore file from branchB into current branch
$ git checkout branchB .gitignore
Увидеть этот пост для получения дополнительной информации.
Я знаю, что я немного поздно, но это мой рабочий процесс для объединения избирательное файлов.
#make a new branch ( this will be temporary)
git checkout -b newbranch
# grab the changes
git merge --no-commit featurebranch
# unstage those changes
git reset HEAD
(you can now see the files from the merge are unstaged)
# now you can chose which files are to be merged.
git add -p
# remember to "git add" any new files you wish to keep
git commit
Простой способ заключается в создании вашего РЕПО на ветку, которую вы хотите объединить с затем работать,
git checkout [branch with file] [path to file you would like to merge]
Если вы запустите
git status
вы увидите файл уже устроили...
Затем запустите
git commit -m "Merge changes on '[branch]' to [file]"
Простой.
Это'ы странно, что ЖКТ еще не имеет такой удобный инструмент, как "из весне. Я использую его в значительной степени при обновлении некоторые старые версии ветке (который до сих пор многие пользователи программного обеспечения) по Просто некоторые исправления ошибок из текущей версии ветке. В этом случае часто возникает потребность быстро получить просто некоторые строк кода из файла в багажник, игнорируя множество других изменений (которые не должны перейти в старую версию)... и конечно интерактивной трехходовой слиянием нужен в данном случае, Git в кассе --патч <филиал> <путь к файлу>
не подходит для этой цели избирательное объединение.
Вы можете сделать это легко:
Просто добавьте эту строку [псевдоним]
в вашем мире.gitconfig хранит настройкии местные
.файл git/config файл`:
[alias]
mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; /C/BCompare3/BCompare.exe $2.theirs $2 $2.base $2; rm -f $2.theirs; rm -f $2.base;' -"
Это означает, что вы использовать не сравнить. Просто изменение программного обеспечения по вашему выбору, если это необходимо. Или вы можете изменить его на три-способ автоматическим слиянием если вы Don'т необходимость взаимодействующие избирательного объединения:
[alias]
mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; git merge-file $2 $2.base $2.theirs; rm -f $2.theirs; rm -f $2.base;' -"
Затем использовать такой:
git mergetool-file <source branch> <file path>
Это даст вам истинный селективный дерево-путь возможность слияния просто файлам в другой ветке.
Это не совсем то, что вы искали, но это было полезно для меня:
git checkout -p <branch> -- <paths> ...
Это микс ответы на некоторые вопросы.
У меня была точно такая же проблема как и упоминаемый вами выше. Но я нашел этот мерзавец блог яснее объяснить ответ.
Команды по ссылке выше:
#You are in the branch you want to merge to
git checkout <branch_you_want_to_merge_from> <file_paths...>
Как насчет ГИТ сброс --мягкий филиала ? Я'м удивлены, что никто не упомянул еще.
Для меня, это'ы самый простой способ, чтобы выборочно забрать изменения из другой ветки, так как эта команда помещает в моем рабочем дереве, все изменения diff и я могу легко забрать или вернуть, что я нужна. Таким образом, у меня есть полный контроль над совершаемыми файлов.
Мне нравится 'ГИТ-интерактивные-слияния' Ответ выше, но там's один легче. Пусть ГИТ сделает это за вас, используя пересоздания комбинации интерактивных и на:
A---C1---o---C2---o---o feature
/
----o---o---o---o master
Так дело же вы хотите C1 и C2 из 'функция' филиал (филиал точка 'Это'), но все остальное сейчас.
# git branch temp feature
# git checkout master
# git rebase -i --onto HEAD A temp
Который, как и выше, вы попадаете в интерактивный редактор, в котором вы выберите 'выбор' линии для C1 и C2 (см. выше). Сохранить и выйти, и тогда она начнет перебазироваться и дать вам филиал 'темп' а также глава в мастер + С1 + С2:
A---C1---o---C2---o---o feature
/
----o---o---o---o-master--C1---C2 [HEAD, temp]
Затем вы можете просто обновить мастер до головы и удалить временные ветки и вы'ре хорошо идти:
# git branch -f master HEAD
# git branch -d temp
Я бы сделала
ГТ ГИТ дифф commit1..commit2 filepattern | ГИТ-применить-индекс &&усилителя&;; коммитов
Таким образом, вы можете ограничить диапазон коммитов для filepattern с ветки.
Украдено из: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
Я знаю, этот вопрос старый и есть много других ответов, но я написал собственный сценарий под названием 'pmerge' для частичного слияния каталогов. Это'работа и я'м все еще учусь Git и написании сценариев для интерпретатора bash.
Эта команда использует Git для слияния-нет фиксации
, а затем unapplies изменения, что Дон'т соответствовать указанному пути.
Использование: ГИТ pmerge ветке путь
Пример: Git для слияния развиваться в src/
Я не'т это тщательно протестированы. Рабочий каталог должен быть свободен от любых несохраненных изменений и неотслеживаемый файлы.
#!/bin/bash
E_BADARGS=65
if [ $# -ne 2 ]
then
echo "Usage: `basename $0` branch path"
exit $E_BADARGS
fi
git merge $1 --no-commit
IFS=$'\n'
# list of changes due to merge | replace nulls w newlines | strip lines to just filenames | ensure lines are unique
for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do
[[ $f == $2* ]] && continue
if git reset $f >/dev/null 2>&1; then
# reset failed... file was previously unversioned
echo Deleting $f
rm $f
else
echo Reverting $f
git checkout -- $f >/dev/null 2>&1
fi
done
unset IFS