Как вишня выбрать диапазон коммитов и слиться в другую ветку?



У меня есть следующий макет репозитория:




  • master branch (производство)

  • интеграция

  • работающего


то, что я хочу достичь, - это выбрать диапазон коммитов из рабочей ветви и объединить его в ветвь интеграции. Я довольно новичок в git, и я не могу понять, как именно это сделать (вишневый выбор диапазонов фиксации в одной операции, а не слияние), не испортив репозиторий. Любые указатели или мысли об этом? Спасибо!

722   7  

7 ответов:

когда дело доходит до ряда коммитов, вишневый сбор ибыл не практично.

как указанных ниже by Кит Ким, Git 1.7.2 + ввел возможность вишневого выбора диапазона коммитов (но вам все равно нужно знать о последствия вишневого сбора для будущего слияния)

git cherry-pick " научился выбирать диапазон коммитов
(например,"cherry-pick A..B" и "cherry-pick --stdin"), так же как и"git revert"; эти не поддерживают более славный sequencing контроль"rebase [-i]" не имеет, хотя.

Дэмианкомментарии и предупреждает нас:

в "cherry-pick A..B" формы A должен быть старше B.
если они неправильный порядок команда будет молча терпеть неудачу.

если вы хотите забрать ряд B через D (включительно) что будет B^..D.
Смотрите "Git создать ветку из диапазона предыдущих коммитов?" в качестве иллюстрации.

как Jubobs упоминает в комментариях:

это предполагает, что B не является корневой фиксацией; вы получите "unknown revision" ошибка в противном случае.

Примечание: начиная с Git 2.9.х/2.10 (3 квартал 2016), вы можете выбрать диапазон фиксации непосредственно на сиротская ветвь (пустая голова): см. "как сделать существующую ветку сиротой в git".


оригинальный ответ (январь 2010 года)

A rebase --onto было бы лучше, когда вы воспроизводите данный диапазон фиксации поверх своей ветви интеграции, как Чарльз Бейли описан здесь.
(кроме того, найдите "вот как вы бы пересадили ветку темы на основе одной ветви в другую" в git rebase man page, чтобы увидеть практический пример git rebase --onto)

если ваша текущая ветка интеграции:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration

что будет воспроизводить все между:

  • после того, как родитель first_SHA-1_of_working_branch_range (отсюда ~1): на первый коммит, который вы хотите воспроизвести
  • до "integration" (который указывает на последний коммит, который вы хотите воспроизвести, с working филиала)

на "tmp" (что указывает на то, где integration указывал раньше)

если есть какой-либо конфликт, когда один из этих коммитов воспроизводится:

  • либо решить ее и запустить"git rebase --continue".
  • или пропустите этот патч, а вместо этого запустите "git rebase --skip"
  • или отменить все вещи с "git rebase --abort " (и положил обратно integration филиала по tmp филиала)

после этого rebase --onto,integration вернется при последней фиксации ветви интеграции (то есть"tmp филиал" + все переигранные коммиты)

с вишневым сбором или rebase --onto, не забывайте, что это имеет последствия для последующих слияний, как описано здесь.


чистая "cherry-pick" решения здесь обсуждается, и будет включать что-то вроде:

если вы хотите использовать патч-подход, то "git format-patch|git am" и "Git cherry" - это ваши варианты.
В настоящее время git cherry-pick принимает только одну фиксацию, но если вы хотите выбрать диапазон B через D что будет B^..D на жаргоне git, так что

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 

но в любом случае, когда вам нужно "воспроизвести" диапазон коммитов, слово "replay" должно подтолкнуть вас к использованию "rebase " особенность Git.

начиная с git v1.7. 2 cherry pick может принимать ряд коммитов:

git cherry-pick научился выбирать диапазон коммитов (например cherry-pick A..B и cherry-pick --stdin), так же git revert; они не поддерживают более хороший контроль последовательности rebase [-i] есть, правда.

вы уверены, что не хотите на самом деле объединить ветки? Если рабочая ветвь имеет некоторые недавние фиксации, которые вы не хотите, вы можете просто создать новую ветвь с головкой в нужной точке.

Теперь, если вы действительно хотите выбрать ряд коммитов, по какой-либо причине, элегантный способ сделать это-просто вытащить набор патчей и применить его к своей новой ветви интеграции:

git format-patch A..B
git checkout integration
git am *.patch

это по существу то, что git-rebase делает в любом случае, но без нужно играть в игры. Вы можете добавить --3way to git-am Если вам нужно объединить. Убедитесь, что нет других *.файлы исправлений уже находятся в каталоге, где вы это делаете, если вы будете следовать инструкциям дословно...

предположим, что у вас есть 2 филиала,

"branchA": включает коммиты, которые вы хотите скопировать (от "commitA"до " commitB"

"branchB": ветвь, которую вы хотите, чтобы коммиты были переданы из"branchA"

1)

 git checkout <branchA>

2) получить идентификаторы "commitA " и"commitB"

3)

git checkout <branchB>

4)

git cherry-pick <commitA>^..<commitB>

5) в случае, если у вас есть конфликт, решить его и введите

git cherry-pick --continue

продолжить процесс сбора вишни.

я завернул код VonC в короткий сценарий bash,git-multi-cherry-pick, для легкого запуска:

#!/bin/bash

if [ -z  ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:   start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order  | while read rev 
do 
  git cherry-pick $rev || break 
done 

В настоящее время я использую это, поскольку я перестраиваю историю проекта, который имел как сторонний код, так и настройки, смешанные вместе в одной магистрали svn. Теперь я разделяю основной сторонний код, сторонние модули и настройки на свои собственные ветви git для лучшего понимания настроек в будущем. git-cherry-pick полезно в этой ситуации, так как у меня есть два дерева в одном хранилище, но без общего предка.

все вышеперечисленные параметры предложат вам разрешить конфликты слияния. Если вы объединяете изменения, совершенные для команды, трудно получить разрешение конфликтов слияния от разработчиков и продолжить. Тем не менее, "git merge" будет выполнять слияние за один выстрел, но вы не можете передать диапазон ревизий в качестве аргумента. мы должны использовать команды "git diff" и "Git apply" для выполнения диапазона слияния оборотов. Я заметил, что "Git apply" потерпит неудачу, если файл патча имеет diff для слишком большого количества файлов, поэтому мы должны создайте исправление для каждого файла, а затем примените его. Обратите внимание, что скрипт не сможет удалить файлы, удаленные в исходной ветке. Это редкий случай, вы можете вручную удалить такие файлы из целевой ветви. Статус выхода "git apply" не равен нулю, если он не может применить патч, однако если вы используете опцию-3way, он вернется к слиянию 3-х способов, и вам не нужно беспокоиться об этом сбое.

Ниже приведен скрипт.

enter code here



  #!/bin/bash

    # This script will merge the diff between two git revisions to checked out branch
    # Make sure to cd to git source area and checkout the target branch
    # Make sure that checked out branch is clean run "git reset --hard HEAD"


    START=
    END=

    echo Start version: $START
    echo End version: $END

    mkdir -p ~/temp
    echo > /tmp/status
    #get files
    git --no-pager  diff  --name-only ${START}..${END} > ~/temp/files
    echo > ~/temp/error.log
    # merge every file
    for file in `cat  ~/temp/files`
    do
      git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
      if [ $? -ne 0 ]
      then
#      Diff usually fail if the file got deleted 
        echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
        echo Skipping the merge: git diff command failed for $file
        echo "STATUS: FAILED $file" >>  /tmp/status
        echo "STATUS: FAILED $file"
    # skip the merge for this file and continue the merge for others
        rm -f ~/temp/git-diff
        continue
      fi

      git apply  --ignore-space-change --ignore-whitespace  --3way --allow-binary-replacement ~/temp/git-diff

      if [ $? -ne 0 ]
       then
#  apply failed, but it will fall back to 3-way merge, you can ignore this failure
         echo "git apply command filed for $file"
       fi
       echo
       STATUS=`git status -s $file`


       if [ ! "$STATUS" ]
       then
#   status is null if the merged diffs are already present in the target file
         echo "STATUS:NOT_MERGED $file"
         echo "STATUS: NOT_MERGED $file$"  >>  /tmp/status
       else
#     3 way merge is successful
         echo STATUS: $STATUS
         echo "STATUS: $STATUS"  >>  /tmp/status
       fi
    done

    echo GIT merge failed for below listed files

    cat ~/temp/error.log

    echo "Git merge status per file is available in /tmp/status"
master:
1234
2345
3456
4567

в отдельную ветку:

git merge -s ours 4567
git merge 2345

Comments

    Ничего не найдено.