Является ли git -svn dcommit после слияния в git опасным?

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

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

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

Ответ 1

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

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

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

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

    git checkout -b work
    
  • фиксировать локально в ветке "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
    
  • rebase главная ветвь с репозиторием SVN (для обновления с сервера SVN)

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

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

    (work)$> git log --graph --oneline --decorate
    
  • Теперь пришло время объединить все три коммиты из ветки "work" в "master", используя эту замечательную опцию --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-чуваков (в противном случае они будут видеть только одно сообщение с сообщением "Объединить работу ветки"

    (master)$> git commit --amend
    
  • Наконец, фиксация на сервере SVN

    (master)$> git svn dcommit
    
  • Вернитесь к работе и, в конечном итоге, восстановите сохраненные файлы:

    (master)$> git checkout work
    (work)$> git stash pop
    

Ответ 2

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

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

  • Закрепить все в ветке темы
  • git svn rebase (разрешить любые конфликты между вашей работой и svn)
  • git мастер проверки
  • git svn rebase (это делает следующий шаг быстрым слиянием, см. ниже комментарии Aaron)
  • git merge topic_branch
  • разрешать любые конфликты слияния (на данный момент их не должно быть)
  • git svn dcommit

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

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

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

Ответ 3

Простое решение: удалите ветвь "work" после слияния

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

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

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

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

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

$> git svn clone <svn-repository-url> <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 commit вместо моего. Вы можете прочитать документацию с помощью "git help rebase" для получения подробной информации. Короче: эта команда сначала открывает редактор, представляющий ваши коммиты ---- просто измените 'pick' на 'squash' для всех тех коммитов, которые вы хотите сквозировать с предыдущими фиксациями. Конечно, первая строка должна оставаться "выборкой". Таким образом, вы можете сконденсировать свои маленькие мелкие фиксации в один или несколько значимых единиц. Сохраните и выйдите из редактора. Вы получите другой редактор с просьбой переписать сообщения журнала фиксации.

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

Чтобы внести изменения в репозиторий svn, я:

$> git checkout master
$> git svn rebase

Теперь мы вернулись в ветвь старого мастера, обновленную со всеми изменениями, которые произошли в среднем в репозитории svn (ваши новые изменения скрыты в ветке "работа" ).

Если есть изменения, которые могут столкнуться с вашими новыми изменениями работы, вы должны разрешить их локально, прежде чем вы сможете нажать свою новую работу (подробнее см. ниже). Затем мы можем изменить наши изменения на 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 'между слиянием и dcommit: если вы попытаетесь удалить ветвь после dcommit, вы получите сообщение об ошибке: Когда вы выполните git svn dcommit ', git забывает, что ваша ветка была объединена с' master '. Вы должны удалить его с помощью "git branch -D work", который не выполняет проверку безопасности.

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

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

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

$> 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 слияния с небольшими первыми шагами в проекте svn с унаследованным.

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

Ответ 4

Ответ Грега Хьюджилла сверху небезопасен! Если какие-либо новые коммиты появились на соединительной линии между двумя "git svn rebase", слияние не будет ускоренной перемоткой вперед.

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

Ответ 5

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

Скажем, у вас есть ветка svn для темы, называемая svn-branch.

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

в этот момент у вас есть все изменения от svn-ветки, раздавленной в одну транзакцию, ожидающую в индексе

git commit

Ответ 6

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

git rebase master topic

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