Как мне объединить подкаталог в 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

Теперь вы можете обрабатывать любые конфликты слияния по своему усмотрению.

Простой обходной путь, объединить и сбросить нежелательные изменения, сохранить то, что вы хотите

  1. У вас есть репозиторий со структурой каталоговgit/src/a,git/src/b, вы хотите только объединить каталог
  2. git merge origin/a-feature-branch
  3. сделать резервную копиюbизменения каталога, напримерmv b b-merged
  4. сбросить ветку командойgit reset HEAD --hard
  5. переопределить каталог b с помощью b-merged,mv b b-origin; mv b-merged b;
Другие вопросы по тегам