Понимание разницы ветвей между SVN и Git

44

Я пользователь SVN и сейчас изучаю Git.

В SVN я обычно оформляю репо на своей локальной машине, который включает все ветви в моем проекте, и я обычно выбирал папку для своей ветки, которая мне интересна, и работал там.

Я вижу разницу с помощью Git.

В настоящее время я клонирую репо и клонирую конкретную ветку, используя gitk.

Папка проекта содержит только содержимое этой ветви, и я не вижу все ветви, как в SVN, что немного смущает меня.

Я не могу найти простой способ увидеть все ветви в моем локальном репозитории с помощью Git.

  • Я хотел бы знать, является ли описанный мной процесс Git «стандартным», а некоторые - насколько правильным, или я что-то упускаю.

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

  • Каковы рекомендуемые соглашения об именах, чтобы клонировать папки, включающие ветку, из репозитория в Git, например myproject-branchname?

Radex
источник
8
Интересно - обычно с SVN вы бы только проверяли ствол или ветку, над которой работаете, но я понимаю, что вы имеете в виду.
HorusKol
20
Вы нарушили рабочий процесс в SVN, теперь вы пытаетесь отразить его в Git (хотя даже хороший SVN-рабочий процесс применим только для Git частично). Лучшее решение - забыть все SVN-привычки и начать в Git с нуля
Lazy Badger
6
git cloneбольше похоже на svnadmin hotcopyили svnrdump+, svnadmin loadчем на это похоже svn checkout. С git, вы не спрашиваете биты и куски из в хранилище; Вы копируете весь репозиторий и работаете с ним локально, передавая изменения обратно в «исходный» репозиторий, когда и когда вам это нравится. Git и Subversion используют две совершенно разные модели для управления исходным кодом.
chepner
1
git-flow
Что
5
@LazyBadger - это не нарушенный рабочий процесс, если он облегчает разработку и обеспечивает ценность. Не существует одного правильного способа использования веток.
dietbuddha

Ответы:

67

Я пользователь SVN и сейчас изучаю GIT.

Добро пожаловать в банду!

SVN перевоспитание

В SVN я обычно [...]

Подожди немного. Хотя CVS и SVN и другие традиционные (то есть централизованные) системы контроля версий выполняют (в основном) ту же цель, что и современные (то есть распределенные) системы контроля версий, такие как Mercurial и Git, вам будет гораздо лучше изучать Git с нуля, а не пытаясь перенести рабочий процесс SVN в Git.

http://hginit.com ( вид на archive.org ) Джоэл Спольски (один из самых основателей Stack Exchange) представляет собой учебник для ртутного, не Git, но это ноль-й главы, «Subversion перевоспитания» является полезно для людей , переключающих от SVN к любой распределенной системе управления версий, так как она говорит вам , что SVN понятия вы должны (временно) ООН -Узнайте (или stashдалеко , так как пользователи Git могли бы сказать) , чтобы быть в состоянии обернуть вокруг головы распределенного концепции системы контроля версий и идиоматические рабочие процессы, созданные для работы с ними.

Таким образом, вы можете прочитать эту нулевую главу и в основном просто заменить слово «ртутный» на «Git» и тем самым должным образом подготовить себя и свой разум к Git.

Мелкий шрифт

(Вы можете пропустить это сейчас.) В то время как ртутный и Git гораздо больше похожи друг на друга , чем SVN, есть есть некоторые концептуальные различия между ними, так что некоторые из заявлений и рекомендаций в «Subversion перевоспитания» станет технически неправильно при замене "mercurial" на "Git":

  • В то время как Mercurial внутренне отслеживает и хранит наборы изменений, Git внутренне отслеживает и сохраняет ревизии (то есть состояния содержимого дерева каталогов), как это делает Subversion. Но кроме Subversion Git выполняет слияния, просматривая различия между каждой участвующей ветвью соответственно и ревизией общего предка (истинное 3-точечное слияние), поэтому результат почти такой же, как и для Mercurial: слияние намного проще и меньше ошибок Чаще, чем в SVN.
  • Хотя вы можете выполнять ветвление в Git путем клонирования репозитория (как это принято в Mercurial), гораздо чаще встречается создание новой ветки в репозитории Git. (Это потому, что ветки Git просто (перемещают) указатели на ревизии, тогда как ртутные ветки - это постоянные метки, применяемые к каждой ревизии. Эти постоянные метки обычно нежелательны, поэтому ртутные рабочие процессы обычно работают путем клонирования полного хранилища для отклонения разработки).

В SVN все является каталогом (но вы не обязательно должны обращаться с ним как с таковым)

Но я тебя перебиваю. Ты говорил?

В SVN я обычно оформляю репо на своей локальной машине, который включает все ветви в моем проекте, и я обычно выбирал папку для своей ветки, которая мне интересна, и работал там.

Если под этим вы имеете в виду, что вы извлекли корневую папку репозитория SVN (или любую другую папку, соответствующую более чем trunkодной ветке или более, например, в обычном макете репозитория SVN branchesпапку, содержащую все не магистральные ветви), тогда Я осмелюсь сказать, что вы, вероятно, неправильно использовали SVN (ish) или, по крайней мере, немного злоупотребили тем фактом, что ствол, ветви и теги все складываются в единое (хотя и иерархическое) пространство имен вместе с каталогами в пределах revisions / codebase.

Хотя может быть заманчиво менять несколько веток SVN параллельно, но это AFAIK, а не то, как SVN предназначен для использования. (Хотя я не уверен в том, какие конкретные недостатки могут работать, как это.)

В Git только каталоги являются каталогами

Каждый клон репозитория Git сам по себе является репозиторием Git: по умолчанию он получает полную копию истории исходного репозитория, включая все ревизии, ветви и теги. Но он сохранит все, что вам нужно: Git хранит его в своей базе данных на основе файлов, расположенной в скрытой .git/подпапке корневой папки хранилища .

Но какие скрытые файлы вы видите в папке хранилища?

Когда вы git cloneхранилище, Git делает несколько вещей. Грубо говоря:

  1. Создает целевую папку , а в ней - .git/подпапку с «базой данных».
  2. Он передает ссылки (теги, ветви и т. Д.) В базу данных исходного репозитория и создает их копию в новой базе данных, давая им слегка измененное имя, помечающее их как «удаленные» ссылки.
  3. Он переносит все ревизии (то есть состояния файлового дерева), на которые указывают эти ссылки, а также все ревизии, на которые эти ревизии указывают напрямую или транзитивно (их родители и предки), в новую базу данных и сохраняет их, так что новые удаленные ссылки фактически указать на то, что доступно в новом хранилище.
  4. Он создает локальную ветку, отслеживающую удаленную ревизию, соответствующую ветви по умолчанию исходного хранилища (обычно master).
  5. Это проверяет это местное отделение.

Этот последний шаг означает, что Git ищет ревизию, на которую указывает эта ветвь, и распаковывает сохраненное там файловое дерево (база данных использует некоторые средства сжатия и дедупликации) в корневую папку хранилища. Эта корневая папка и все ее подпапки (кроме специальной .gitподпапки) называются «рабочей копией» вашего репозитория. Вот где вы взаимодействуете с содержимым текущей проверенной ревизии / ветки. Это просто обычные папки и файлы. Однако для взаимодействия с самим хранилищем («база данных» ревизий и ссылок) вы используете gitкоманды.

Просмотр веток Git и взаимодействие с ветками Git

В настоящее время я клонирую репо и клонирую конкретную ветку, используя gitk.

Версия, которую gitkя получил, не может клонировать репозитории. Он может только просматривать историю репо и создавать филиалы и проверять филиалы. Также нет «клонирования» ветки. Вы можете только клонировать репозитории.

Вы имели в виду, что вы клонируете репо, используя, git clone ...а затем, используя gitk, проверяете ветку?

Папка проекта содержит только содержимое этой ветви, и я не вижу все ветви, как в SVN, что немного смущает меня.

[...]

  • Я хотел бы знать, является ли описанный мною процесс git «стандартным», а некоторые - насколько правильным [...]

Да, это довольно стандартно:

  • Клонировать репозиторий, используя git clone ...
  • Проверьте ветку, с которой вы хотите работать, git checkout ...или используйте графический инструмент, такой какgikt

Я не могу найти простой способ увидеть все ветви в моем локальном репозитории с помощью GIT.

  • [...] или я скучаю по smt.

Может быть:

  • Вы можете перечислить местные филиалы с git branch
  • Вы можете перечислить удаленные ветви с git branch -rили все ветви сgit branch -a
  • вы можете использовать gitkдля просмотра полной истории (все метки веток и т. д., о которой знает ваше локальное хранилище), вызвав ее с

    gitk --all
    

Как работать с несколькими ветками параллельно

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

Здесь есть разные сценарии:

Новое (еще не созданное) изменение необходимо применить к нескольким веткам

Используйте этот рабочий процесс:

  1. Создайте новую ветку cиз ревизии, которая уже находится в предке всех этих ветвей (например, ревизия, которая внесла ошибку, когда изменение будет исправлено), или из ревизии, которая (включая всех ее предков) приемлема для введения в все эти ветви.
  2. Сделайте и передайте изменения в этой новой ветви c.
  3. Для каждой ветви, bкоторая нуждается в изменении:

    1. Проверьте b:

      git checkout b
      
    2. Объединить cв b:

      git merge c
      
  4. Удалить ветку c:

    git branch --delete c
    

Существующее изменение необходимо в другой ветке

(... но без других изменений, внесенных в то место, где находится это изменение)

  1. Проверьте ветку, где необходимо изменение
  2. Cherry-выберите ревизию (ы), вносящие изменения, в порядке

В одной ветви aвы хотите изменить один или несколько файлов на точное состояние, которое они имеют в другой ветвиb

  1. Проверять, выписываться a
  2. Получить содержимое файла из ветки b:

    git checkout b -- path/to/a/file.txt path/to/another/file.cpp or/even/a/complete/directory/ ...
    

    (За исключением git checkoutслучаев без передачи путей, это не переключит на ветвь b, а только получит оттуда запрошенное содержимое файла. Эти файлы могут существовать или не существовать a. Если они есть, они перезаписываются с включенным содержимым b.)

Работая над одной веткой, вы хотите посмотреть, как обстоят дела в другой ветке

Проверьте ветку, над которой вы хотите работать.

Затем, чтобы посмотреть на другую ветку,

  • либо используйте графические инструменты, которые позволяют просматривать содержимое не проверенных в настоящий момент ревизий (например, при gitkпопытке переключить переключатели с «патча» на «дерево»)
  • или клонировать репозиторий во временный каталог и проверить там другую ветку
  • или используйте git worktreeдля создания отдельного рабочего каталога того же хранилища (то есть, также используя базу данных в .git/каталоге вашего текущего локального хранилища), где вы можете проверить эту другую ветку
Дас-г
источник
Для последнего рабочего процесса, stashидеально.
CAD97
@ CAD97 нет , если вы хотите продолжить работу над первой ветвью, глядя на секунду для справки параллельно . git stashЭто хорошо, чтобы убрать незаконченную работу с дороги, например, чтобы поменять ветки и вернуться позже.
Дас-г
1
«Рабочие процессы Mercurial обычно работают путем клонирования полного репозитория для отклоняющихся разработок» - о, я слышал об этом, но большинство людей, которым нужны ветки Git, просто используют закладки, а не клонируют весь репозиторий. Это намного проще.
Кевин
@Kevin Это может быть. Некоторое время назад я в последний раз использовал Mercurial, так что, может быть, тогда все было иначе. (Или, может быть, это были рабочие процессы сообщества, с которым я использовал его, которые были такими
das-g
Может быть, текст Hg Init «[...] потому что вы действительно должны были разветвлять Mercurial путем клонирования репозиториев [...]», также должен быть обновлен в этом отношении.
Дас-г
31

В SVN я обычно оформляю репо на своей локальной машине, который включает все ветви в моем проекте, и я обычно выбирал папку для своей ветки, которая мне интересна, и работал там.

Если вы не проверите каталог выше транка, в Subversion у вас обычно не все локальные ветки доступны. В Git весь контент (коммиты, сообщения, ветки и т. Д.) Всегда клонируется в каждую копию.

В настоящее время я клонирую репо и клонирую конкретную ветку, используя gitk.

Не возможно, см. Выше. Вы можете git checkout branch-name, но не можете git clone something branch-name. В Subversion ветки - это папки. В Git ветки являются указателями на коммит.

Я не могу найти простой способ увидеть все ветви в моем локальном репозитории с помощью GIT.

Беги git branch. По умолчанию он показывает только локальные филиалы. Используйте, git branch --remoteчтобы увидеть удаленные ветви.

l0b0
источник
4
Гектометр «По умолчанию отображаются только локальные ветви». Похоже, есть другие типы ветвей, которые не являются локальными. Но вы также говорите: «В Git весь контент (коммиты, сообщения, ветки и т. Д.) Всегда клонируется в каждую копию». , Я нахожу это немного запутанным, потому что, если все ветви клонируются в вашей копии, что это за таинственные нелокальные ветви? Может быть, это слишком сложно, чтобы ответить в поле для комментариев.
труба
2
@pipe Когда вы фиксируете изменения, вы делаете это, создавая локальный коммит, который изменяет коммит, на который указывает ветка. Если вы хотите, чтобы другие получили эти изменения, вам нужно отправить эти изменения в удаленный репозиторий. Это приводит к удаленной ветви, указывающей на этот новый коммит. Теперь все остальные могут вытащить эти изменения оттуда, и в результате каждый в конечном итоге получит полную копию хранилища
Frozn
9
@pipe Во-первых, вы можете клонировать только ветку, используя --single-branchтолько (даже только подсказку --depth 1). Разница между локальной и удаленной ветками, известными git, является всего лишь разновидностью метки. Удаленные ветви имеют префикс с именем удаленного источника (часто origin). Местные филиалы не имеют этого префикса. Но, в конце концов, данные доступны локально (если вы не сделали --single-branchили что-то подобное). Когда вы работаете git checkout $branchnameс веткой, для которой нет локальной, но удаленной ветки, git автоматически устанавливает локальную ветку, «отслеживающую» удаленную.
Йонас Шефер
«Если вы не проверите каталог над транком» - мой опыт показывает, что это довольно часто, так как это значительно облегчает слияние. (Хотя вместо тегов версий мы используем одну «живую» ветвь, поэтому обычно она составляет всего 2-3 копии кода)
Изката,
1
@Izkata "это облегчает слияние", не так ли?
HorusKol
3

Поскольку это помечено я надеюсь, что мое отсутствие знаний SVN пренебрежимо мало.

В настоящее время я клонирую репо и клонирую конкретную ветку, используя gitk.

Вы клонируете весь удаленный репозиторий, а не только конкретную ветку.

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

Команда fetchиспользуется для синхронизации локальной базы данных с удаленной.

Обычно из этой локальной базы данных вы извлекаете ветку для работы. Это не что иное, как внутренний маркер для git, с которого началась ваша текущая работа.

Скажем, вы работаете над простым репозиторием, в котором кроме ветки нет master, вы можете заглянуть в .gitпапку, чтобы раскрыть «магию»:

Предположим, что ваш последний коммит (on master) был 182e8220b404437b9e43eb78149d31af79040c66, вы найдете именно это под cat .git/refs/heads/master.

git checkout -b mybranchПосле того, как вы откроете новую ветку , вы найдете точно такой же указатель в файле cat .git/refs/heads/mybranch.

Ветви - это не что иное, как указатели. «Рабочий» маркер называется HEAD.

Если вы хотите знать, где вы находитесь HEAD:

cat .git/HEADкоторый говорит, например ref: refs/heads/mybranch, который в свою очередь указывает ( cat .git/refs/heads/mybranch) на хеш коммита78a8a6eb6f82eae21b156b68d553dd143c6d3e6f

Фактические коммиты хранятся в objectsпапке (как это отдельная тема).

Папка проекта содержит только содержимое этой ветви, и я не вижу все ветви, как в SVN, что немного смущает меня.

Не путайте working directoryс «git-database» в целом. Как я уже говорил выше, ваш рабочий каталог - это только снимок (может быть) подмножества.

Скажем, у вас есть разные ветки, ваш рабочий каталог предназначен для работы только с этой веткой (хотя вы можете поместить работу оттуда в другое место).

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

  • git branch для местных филиалов
  • git branch --remote для удаленных филиалов
  • git branch -a для обоих

(или git branch -v)

Поскольку git является распределенной системой контроля версий, не только возможно, но и рекомендуется создавать различные ветви локально / удаленно.

Мой типичный рабочий процесс:

  • ответвление
  • ветка WIP (работа в процессе) ветка от этого
  • работать так, как вы хотите - даже если вы делаете коммит после одной строки; это не важно

Когда функция завершена:

  • сквош / переделать WIPветку (с интерактивным перебазированием) = сделать один коммит из этого
  • объедините WIPветку с веткой возможностей и предложите (если вы работаете с github это предложение будет называться «запросом по запросу») интегрироваться в стабильную (основную) ветку.

Также я хотел бы знать, как обрабатывать процесс, в котором мне нужно одновременно wprl для двух веток в случае, например, если мне нужно сделать исправление на master, но также сохранить содержимое другой ветки.

Это зависит от того, как ваш проект структурирован:

Скажем, у вас есть стабильный мастер. А функции разрабатываются только из этой стабильной ветки, поэтому обычно они находятся за веткой функций. Тогда у вас будет последний коммит на master, который будет корнем ветви возможностей.

Затем вы сделаете коммит в основной ветке и сможете решить, объединить ли обе ветви вместе или перебазировать (что является своего рода объединением для пользователей с, так сказать, сложными потребностями).

Или вы всегда можете вносить изменения в ветви (например master) и вставлять их в другие ветви.

Что такое рекомендуемое соглашение об именах для создания клонированных папок, включающих ветку из репозитория в GIT, например myproject-branchname

Это тебе решать.

Как правило, вы в конечном итоге с именем хранилища.

Но бывают случаи, когда этого не хотят:

например, вы клонируете oh-my-zsh с помощью git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh Здесь .oh-my-zshпрямо названа цель.

Томас Джанк
источник
2

Git clone фактически клонирует весь репозиторий, но устанавливает ваш рабочий каталог по умолчанию (обычно master).

Вы можете видеть другие ветви, используя, git branchчтобы видеть локальные ветви или git branch -rвидеть удаленные, а затем git checkoutпереключаться на существующую ветку или создавать новую, основываясь на текущей ветке.

Вы должны прочитать git документацию для получения более подробной информации, и у Atlassian есть несколько хороших статей об этом.

HorusKol
источник
0

Ветки в git и svn - это принципиально разные вещи.

В SVN филиал (или тег) является каталогом в репо.

В git ветвь (или тег) - это указатель на коммит.

С svn вы можете, если хотите, проверить корень репо. Это означает, что вы отметили каждую ветку и тег сразу. На самом деле это не обычный способ использовать SVN.

Ветвь git не является каталогом, поэтому нет эквивалента «проверке корня репо». Существует некоторая поддержка нескольких рабочих деревьев, поэтому я думаю, что вы могли бы собрать скрипт, чтобы оформить каждую ветку в одно и то же время, если бы вы действительно этого хотели, но это было бы довольно необычно.

Кроме того, с SVN существует ровно один репо. С git у каждого разработчика есть свой репо. Это означает, что разработчики могут работать в автономном режиме, но это также означает, что разные разработчики могут иметь разное представление о том, что находится в каждой ветви.

Благодаря тому, что каталоги и простая линейная модель истории svn, ветви svn имеют надежную историю. Если вы хотите узнать, что было на ветке x на дату y, вы можете легко задать этот вопрос.

С другой стороны, у веток Git нет истории. Существует «reflog», но он предназначен скорее как механизм аварийного восстановления, чем долгосрочная история. В частности, reflog не может быть прочитан удаленно и по умолчанию отключен для пустых репозиториев.

Конечно, у комитетов есть истории, но этих историй недостаточно, чтобы ответить на вопрос «что было на ветке х репо у на дату z».

Я не могу найти простой способ увидеть все ветви в моем локальном репозитории с помощью Git.

Вы можете получить список всех локальных веток, набрав "git branch".

Вы можете перечислить все ветви как локальные, так и удаленные, используя "git branch -a"

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

Пара вариантов.

Вы можете зафиксировать свои изменения в «другой ветке», переключиться на master и выполнить свою работу там, а затем переключиться обратно.

Вы также можете создать дополнительное рабочее дерево. Google "git-worktree" для деталей о синтаксисе.

Каковы рекомендуемые соглашения об именах для создания клонированных папок, включающих ветку из репозитория в Git, например myproject-branchname?

Я не думаю, что существует установленная конвенция. Проверка нескольких рабочих деревьев одновременно является исключением, а не правилом.

Питер Грин
источник
2
этот ответ выглядит неполным, почему?
комар