Как мне объединить подкаталог в git?
Можно ли объединить только изменения для подкаталога из локальной ветви git в удаленную ветку git или это "все или ничего"?
Например, у меня есть:
branch-a
- content-1
- dir-1
- content-2
а также
branch-b
- content-1
- dir-1
- `content-2
Я хочу только объединить содержимое branch-a dir-1 с содержимым branch-b dir-1.
9 ответов
Так же, как альтернатива SO-вопросу " Как объединить отдельные файлы с помощью git-merge? ", Я только что нашел этот поток GitHub, который может быть более приспособлен для объединения целого подкаталога на основе git read-tree:
Мой репозиторий =>
cookbooks
Мой целевой каталог хранилища =>cookbooks/cassandra
Удаленный репозиторий =>
infochimps
Источник удаленного репозитория, в который я хочу объединитьсяcookbooks/cassandra
=>infochimps/cookbooks/cassandra
Вот команды, которые я использовал для их объединения
- Добавьте репозиторий и получите его
git remote add -f infochimps git://github.com/infochimps/cluster_chef.git
- Выполнить слияние
git merge -s ours --no-commit infochimps/master
- Только слияние
infochimps/cookbooks/cassandra
вcassandra
git read-tree --prefix=cassandra/ -u infochimps/master: кулинарные книги /cassandra
- Зафиксируйте изменения
git commit -m 'объединение в infochimps cassandra'
добавление
Это странно, [редактировать меня] - но read-tree
шаг может потерпеть неудачу, как это:
error: Entry 'infochimps/cookbooks/cassandra/README' overlaps with 'cookbooks/cassandra/README'. Cannot bind.
... даже когда оба файла идентичны. Это может помочь:
git rm -r cassandra
git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra
Но, конечно же, проверьте вручную, что это делает то, что вы хотите.
Для моего примера предположим, что у вас есть ветвь 'source' и ветвь 'destination', которые оба отражают свои исходные версии (или нет, если только локальные) и тянутся до самого последнего кода. Допустим, мне нужен подкаталог в репозитории с именем newFeature, который существует только в ветке 'source'.
git checkout destination
git checkout source newFeature/
git commit -am "Merged the new feature from source to destination branch."
git pull --rebase
git push
Значительно менее запутанный, чем все остальное, что я видел, и это отлично сработало для меня, найденное здесь.
Обратите внимание, что это не "реальное слияние", поэтому у вас не будет информации о коммитах newFeature в целевой ветви, только изменения файлов в этом подкаталоге. Но так как вы, вероятно, собираетесь позже объединить всю ветку или отбросить ее, это может не быть проблемой.
Учитывая сценарий OP, в котором у них есть две ветки, но они хотят объединить только историю dir-1 из ветки-a в ветку-b:
# Make sure you are in the branch with the changes you want
git checkout branch-a
# Split the desired folder into its own temporary branch
# This replays all commits, so it could take a while
git subtree split -P dir-1 -b temp-branch
# Enter the branch where you want to merge the desired changes into
git checkout branch-b
# Merge the changes from the temporary branch
git subtree merge -P dir-1 temp-branch
# Handle any conflicts
git mergetool
# Commit
git commit -am "Merged dir-1 changes from branch-a"
# Delete temp-branch
git branch -d temp-branch
Использование git cherry-pick
выбрать коммиты, которые вы хотите, и объединить только эти коммиты. Ключевой трюк заключается в том, чтобы получить эти коммиты простым способом (чтобы вам не приходилось выяснять их, вручную проверяя журнал git и вводя их вручную). Вот как: использовать git log
напечатать идентификатор sha1 коммита, например так:
git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>
commit-a - это коммит непосредственно перед начальной точкой ветвления для слияния, commit-b - последний коммит в ветке для слияния. --reverse печатает эти коммиты в обратном порядке для выбора вишни позже.
Затем сделайте это так:
git cherry-pick $(git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>)
Два шага, простой и стабильный!
Я получил это из ветки форума на Eclipse, и это сработало как шарм:
git checkout source-branch
git checkout target-branch <directories-or-files-you-do-**NOT**-want>
git commit
git checkout target-branch
git merge source-branch
Создать репозиторий Git содержит как филиал-а и филиал-б
git checkout branch-a
git diff branch-b dir-1 > a.diff
patch -R -p1 < a.diff
Случай 0: я еще не трогал файлы
git checkout origin/branch-with-the-code-you-want ./path/to/dir1
Это даст вам папку, как в другой ветке неустановленных изменений.
Случай 1: команда имеет чистые коммиты
Если ваша команда выполняет чистые коммиты, то поиск коммитов в истории может быть плодотворным. Использовать
git cherry-pick COMMIT_HASH
для тех случаев. Вы можете захотеть
git rebase -i HEAD~N
где N - некоторое количество коммитов, чтобы добавить их как
pick COMMIT_HASH
строчки в истории, если нужно.
Случай 2: Чистые коммиты не важны, но знание конфликтов важно.
Если у вас есть все коммиты повсюду, вам, вероятно, не нужно будет хранить историю, вот один подход, который работает для этих случаев. Обратите внимание, что этот подход не удаляет файлы и не дает вам историю, но он дает вам конфликты между каждым файлом.
# Create an orphan branch with no history but your files
git checkout --orphan temp-branch
# Get the version of the files from the other branch
git checkout origin/branch-with-the-changes ./path/to/the/folder/you/want/to/merge
git commit -m "Commit that has all files like they are on your branch, except that one folder you want to merge"
# Merge the other file tree
git checkout your-branch
git merge temp-branch --allow-unrelated
# Clean up
git branch -D temp-branch
Вот как я бы это решил:
Сначала найдите последний коммит, общий для обеих ветвей, здесь две ветки начинают расходиться:
$ git merge-base branchA branchB
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2
Затем извлеките новую ветку из этого коммита:
git branch branchC 050dc022f3a65bdc78d97e2b1ac9b595a924c3f2
Затем извлеките папку, которую вы хотите объединить из исходной ветки в новую ветку:
git checkout branchC
git checkout branchB ./path/to/the/folder/you/want/to/merge
git commit -m "update folder to merge from branchB"
Теперь ветка C содержит только изменения из папки, которую вы хотите объединить.
Наконец, объедините эти изменения в целевую ветку:
git checkout branchA
git merge branchC
Теперь вы можете обрабатывать любые конфликты слияния по своему усмотрению.
Простой обходной путь, объединить и сбросить нежелательные изменения, сохранить то, что вы хотите
- У вас есть репозиторий со структурой каталогов
git/src/a
,git/src/b
, вы хотите только объединить каталог -
git merge origin/a-feature-branch
- сделать резервную копию
b
изменения каталога, напримерmv b b-merged
- сбросить ветку командой
git reset HEAD --hard
- переопределить каталог b с помощью b-merged,
mv b b-origin; mv b-merged b;