Опасно ли git-svn dcommit после слияния с git? - PullRequest
133 голосов
/ 10 октября 2008

Моя мотивация попробовать git-svn - это легкое слияние и ветвление. Затем я заметил, что мужчина git-svn (1) говорит:

Запускать git-merge или git-pull НЕ рекомендуется на ветке, которую вы планируете приехать из. Subversion не представляет слияния ни в одном разумный или полезный способ; поэтому пользователи, использующие Subversion, не могут видеть слияния вы сделали. Кроме того, если вы слиться или вытащить из мерзавца ветвь, которая является зеркалом ветки SVN, dcommit может зафиксировать неправильная ветвь.

Означает ли это, что я не могу создать локальную ветку из svn / trunk (или ветви), взломать, объединить обратно в svn / trunk, а затем dcommit? Я понимаю, что пользователи svn увидят тот же беспорядок, который всегда был в svn pre 1.5.x, но есть ли другие недостатки? Последнее предложение меня тоже волнует. Люди обычно делают такие вещи?

Ответы [ 6 ]

173 голосов
/ 21 ноября 2010

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

Мой новый рабочий процесс теперь выглядит следующим образом:

  • У меня есть "основная" ветвь, единственная ветвь, от которой я коммитую и которая клонирует SVN-репозиторий (-s предполагается, что в репозитории есть стандартная компоновка SVN trunk/, branches/, и tags/):

    git svn clone [-s] <svn-url>
    
  • Я работаю над локальной веткой "Работа" (-b создает ветку "Работа")

    git checkout -b work
    
  • локальная фиксация в ветке "работа" (-s для подтверждения вашего сообщения о фиксации). В дальнейшем я предполагаю, что вы сделали 3 локальных коммита

    ...
    (work)$> git commit -s -m "msg 1"
    ...
    (work)$> git commit -s -m "msg 2"
    ...
    (work)$> git commit -s -m "msg 3"
    

Теперь вы хотите зафиксировать на сервере SVN

  • [В конце концов] спрятать изменения, которые вы не хотите видеть зафиксированными на SVN-сервере (часто вы комментировали некоторый код в основном файле только потому, что вы хотите ускорить компиляцию и сосредоточиться на конкретной функции)

    (work)$> git stash
    
  • перебазировать основную ветку с хранилищем SVN (для обновления с сервера SVN)

    (work)$> git checkout master
    (master)$> git svn rebase
    
  • вернуться в рабочую ветку и выполнить перезагрузку с мастером

    (master)$> git checkout work
    (work)$> git rebase master
    
  • Убедитесь, что все в порядке, например:

    (work)$> git log --graph --oneline --decorate
    
  • Теперь пришло время объединить все три коммита из ветви "работа" в "мастер", используя эту замечательную опцию --no-ff

    (work)$> git checkout master
    (master)$> git merge --no-ff work
    
  • Вы можете заметить статус журналов:

    (master)$> git log --graph --oneline --decorate
    * 56a779b (work, master) Merge branch 'work'
    |\  
    | * af6f7ae msg 3
    | * 8750643 msg 2
    | * 08464ae msg 1
    |/  
    * 21e20fa (git-svn) last svn commit
    
  • Теперь вы, вероятно, захотите отредактировать (amend) последний коммит для ваших SVN-парней (в противном случае они увидят только один коммит с сообщением "Merge branch 'work'" *

    (master)$> git commit --amend
    
  • Окончательно зафиксировать на сервере SVN

    (master)$> git svn dcommit
    
  • Вернитесь к работе и, в конце концов, восстановите ваши спрятанные файлы:

    (master)$> git checkout work
    (work)$> git stash pop
    
49 голосов
/ 10 октября 2008

Создание локальных веток определенно возможно с помощью git-svn. Пока вы просто используете локальные ветки и не пытаетесь использовать git для слияния между вышестоящими ветвями SVN, все будет в порядке.

У меня есть ветка "master", которую я использую для отслеживания сервера svn. Это единственная ветка, из которой я делаю коммит. Если я делаю какую-то работу, я создаю ветку тем и работаю над ней. Когда я хочу зафиксировать это, я делаю следующее:

  1. Зафиксируйте все в ветке темы
  2. git svn rebase (разрешите все конфликты между вашей работой и svn)
  3. мастер проверки git
  4. git svn rebase (это делает следующий шаг быстрым слиянием, см. Комментарии Аарона ниже)
  5. git merge topic_branch
  6. разрешить любые конфликты слияния (на данный момент их не должно быть)
  7. git svn dcommit

У меня также есть другая ситуация, когда мне нужно сохранить некоторые локальные изменения (для отладки), которые никогда не должны передаваться в svn. Для этого у меня есть вышеупомянутая основная ветка, но также есть ветка под названием "работа", где я обычно работаю. Тематические ветки разветвлены от работы. Когда я хочу зафиксировать работу там, я извлекаю master и использую cherry-pick, чтобы выбрать коммиты из рабочей ветки, которые я хочу зафиксировать в svn. Это потому, что я хочу избежать фиксации трех локальных изменений. Затем я делаю коммит из ветки master и перебазирую все.

Стоит сначала запустить git svn dcommit -n, чтобы убедиться, что вы собираетесь совершить именно то, что намереваетесь совершить. В отличие от git, переписывать историю в svn сложно!

Я чувствую, что должен быть лучший способ объединить изменения в ветке темы с пропуском этих локальных изменений, чем при использовании cherry-pick, поэтому, если у кого-то есть идеи, они будут приветствоваться.

33 голосов
/ 28 декабря 2010

Простое решение: удалить ветку 'work' после объединения

Краткий ответ: Вы можете использовать git так, как вам нравится (простой рабочий процесс см. Ниже), включая слияние. Просто убедитесь, что для удаления временной рабочей ветки следите за каждым ' git merge work ' с ' git branch -d work '.

Исходное объяснение: Проблема слияния / dcommit состоит в том, что всякий раз, когда вы 'git svn dcommit' ветвь, история слияния этой ветки "сплющивается": git забывает обо всех операциях слияния, которые пошли в эту ветку: сохраняется только содержимое файла, но факт что этот контент (частично) пришел из определенной другой ветки, теряется. См .: Почему git svn dcommit теряет историю коммитов слияния для локальных веток?

(Примечание: git-svn мало что может с этим поделать: svn просто не понимает гораздо более мощных git-слияний. Поэтому в хранилище svn эта информация о слиянии не может быть представлена ​​каким-либо образом.)

Но это проблема целом . Если вы удалите ветку 'work' после того, как она будет объединена с 'master веткой', то ваш репозиторий git будет на 100% чист и выглядит точно так же, как ваш svn-репозиторий.

Мой рабочий процесс: Конечно, я сначала клонировал удаленный svn-репозиторий в локальный git-репозиторий (это может занять некоторое время):

$> git svn clone <svn-repository-url> <local-directory>

Затем вся работа происходит внутри "local-directory". Всякий раз, когда мне нужно получить обновления с сервера (например, 'svn update'), я делаю:

$> git checkout master
$> git svn rebase

Я делаю всю свою работу по разработке в отдельной ветке 'работа', которая создается так:

$> git checkout -b work

Конечно, вы можете создавать столько веток для своей работы, сколько захотите, а также объединять и перебазировать их между собой, как захотите (просто удалите их, когда закончите с ними - как описано ниже). В своей обычной работе я совершаю очень часто:

$> git commit -am '-- finished a little piece of work'

Следующий шаг (git rebase -i) является необязательным - это просто очистка истории перед ее архивированием на svn: Как только я достиг стабильного милиного камня, которым хочу поделиться с другими, я переписываю историю этого ветка 'работа' и очистка сообщений коммита (другим разработчикам не нужно видеть все маленькие шаги и ошибки, которые я сделал на пути - только результат). Для этого я делаю

$> git log

и скопируйте хэш sha-1 последнего коммита, который находится в репозитории svn (как указано в git-svn-id). Тогда я звоню

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb

Просто вставьте хэш sha-1 нашего последнего коммита svn вместо моего. Вы можете прочитать документацию с помощью git help rebase для подробностей. Вкратце: эта команда сначала открывает редактор, представляющий ваши коммиты ---- просто измените 'pick' на 'squash' для всех тех коммитов, которые вы хотите раздавить с предыдущими коммитами. Конечно, первая строка должна оставаться в качестве «выбора». Таким образом, вы можете сконцентрировать ваши многочисленные маленькие коммиты в одну или несколько значимых единиц. Сохраните и выйдите из редактора. Вы получите другой редактор с просьбой переписать сообщения журнала фиксации.

Короче говоря: после того, как я закончу «взлом кода», я массирую свою ветку «работа», пока она не увидит, как я хочу представить ее другим программистам (или как я хочу увидеть работу через несколько недель, когда просмотреть историю).

Чтобы отправить изменения в репозиторий svn, я делаю:

$> git checkout master
$> git svn rebase

Теперь мы вернулись к старой ветке 'master', обновленной со всеми изменениями, произошедшими за это время в репозитории svn (ваши новые изменения скрыты в ветке 'work').

Если есть изменения, которые могут конфликтовать с вашими новыми «рабочими» изменениями, вам нужно разрешить их локально, прежде чем вы сможете отправить свою новую работу (подробности см. Ниже). Затем мы можем отправить наши изменения в SVN:

$> git checkout master
$> git merge work        # (1) merge your 'work' into 'master'
$> git branch -d work    # (2) remove the work branch immediately after merging
$> git svn dcommit       # (3) push your changes to the svn repository

Примечание 1. Команда 'git branch -d work' совершенно безопасна: она позволяет вам удалять только те ветки, которые вам больше не нужны (потому что они уже объединены с вашей текущей веткой). Если вы выполнили эту команду по ошибке до объединения вашей работы с веткой 'master', вы получите сообщение об ошибке.

Примечание 2: Обязательно удалите ветку с помощью 'git branch -d work' между merging и dcommit: если вы попытаетесь удалить ветку после dcommit, вы получите сообщение об ошибке: Когда вы делаете 'git svn dcommit', git забывает, что ваша ветка была объединена с 'master'. Вы должны удалить его с помощью 'git branch -D work', который не выполняет проверку безопасности.

Теперь я немедленно создаю новую ветку 'work', чтобы избежать случайного взлома ветки 'master':

$> git checkout -b work
$> git branch            # show my branches:
  master
* work

Интеграция вашей «работы» с изменениями в SVN: Вот что я делаю, когда «git svn rebase» показывает, что другие изменили хранилище svn, когда я работал над моей веткой «работа»:

$> git checkout master
$> git svn rebase              # 'svn pull' changes
$> git checkout work           # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master            # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed

$> git checkout master         # try again to push my changes
$> git svn rebase              # hopefully no further changes to merge
$> git merge integration       # (1) merge your work with theirs
$> git branch -d work          # (2) remove branches that are merged
$> git branch -d integration   # (2) remove branches that are merged
$> git svn dcommit             # (3) push your changes to the svn repository

Существуют более мощные решения: Представленный рабочий процесс упрощен: он использует возможности git только в каждом раунде «update / hack / dcommit» - но оставляет долгосрочную историю проекта столь же линейной, как и хранилище svn. Это нормально, если вы просто хотите начать использовать git merges небольшими первыми шагами в старом проекте svn.

Когда вы познакомитесь с git merging, не стесняйтесь исследовать другие рабочие процессы: если вы знаете, что делаете, вы можете смешивать git merges с svn merges ( Использование git-svn ( или подобное) просто чтобы помочь с SVN слияния? )

8 голосов
/ 16 декабря 2010

Greg Hewgill ответ сверху небезопасен! Если между двумя «git svn rebase» в транке появятся какие-либо новые коммиты, слияние не будет ускоренным.

Это может быть обеспечено использованием флага "--ff-only" для git-merge, но я обычно не запускаю "git svn rebase" в ветке, а только "git rebase master" (если предположить, что это только местный филиал). Тогда после этого "git merge thebranch" будет гарантированно ускорен.

6 голосов
/ 06 октября 2009

Безопасный способ объединить svn-ветки в git - это использовать git merge --squash. Это создаст один коммит и остановит вас, чтобы добавить сообщение.

Допустим, у вас есть ветка svn для темы, которая называется svn-branch.

git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch

на данный момент у вас есть все изменения из svn-branch, сжатые в один коммит, ожидающий в индексе

git commit
5 голосов
/ 11 марта 2010

Переместите локальную ветку git на главную ветку git, затем dcommit, и похоже, что вы сделали все эти коммиты последовательно, чтобы svn люди могли видеть это линейно, как они привыкли. Итак, если у вас есть локальная ветка с названием topic, вы можете сделать

git rebase master topic

, который затем воспроизведет ваши коммиты через главную ветку, готовую для вас, чтобы dcommit

...