Git для пользователей Perforce

Я использую Perforce в течение нескольких лет. Я хотел бы переключиться на использование git для моего личного кода, но все обучающие программы git, которые я видел, либо предполагают, что вы полный источник управления n00b (что делает их невероятно утомительными), либо что вы "Используется для svn (чего я не знаю).

Я знаю p4, и я также понимаю идею распределенной системы управления источниками (так что мне не нужна коммерческая подача, спасибо). Я бы хотел, чтобы это была таблица перевода из команды p4 в эквивалентные команды git, а также команды "не могут жить без", которые не имеют эквивалента p4.

Поскольку я подозреваю, что каждый пользователь p4 использует другое подмножество p4, вот некоторые из вещей, которые я регулярно делаю в p4, которые я хотел бы сделать в git, которые не сразу очевидны из документов Я посмотрел:

  • создать несколько ожидающих списков изменений в одном клиенте. (p4 change)
  • изменить ожидающий список изменений. (также p4 change)
  • см. список всех моих ожидающих списков изменений (p4 changes -s pending)
  • список всех измененных файлов моего клиента (p4 opened) или в ожидающем списке изменений (p4 describe)
  • см. разницу ожидающего списка изменений (я использую оболочку script для этого, которая использует p4 diff и p4 describe)
  • для данного файла, см., какие представленные списки изменений повлияли на строки (p4 annotate)
  • для данного файла, см. список описаний списков изменений, которые повлияли на файл (p4 log)
  • отправить ожидающий список изменений (p4 submit -c)
  • прервать ожидающий список изменений (p4 revert)

Многие из них вращаются вокруг "списков изменений". "changelist" - терминология p4. Что эквивалентно термину git?

Похоже, что ветки могут быть пользователями git вместо того, что p4 вызывает списки изменений. Немного сбивает с толку, поскольку p4 также имеет что-то, называемое веткой, хотя они кажутся лишь смутно связанными понятиями. (Хотя я всегда считал, что концепция ветки p4 довольно странная, она опять же отличается от классической концепции RCS ветки.)

В любом случае... Я не уверен, как выполнить то, что я обычно делаю в списках изменений p4 с ветвями git. В p4 я могу сделать что-то вроде этого:

$ p4 edit a.txt
$ p4 change a.txt
Change 12345 created.

В этот момент у меня есть чардж-лист, содержащий a.txt. Я могу редактировать описание и продолжать работу, не отправляя список изменений. Кроме того, если выясняется, что мне нужно внести некоторые изменения в некоторые другие файлы, например сказать bugfix в каком-то другом слое кода, я могу сделать это в одном клиенте:

$ p4 edit z.txt
$ p4 change z.txt
Change 12346 created.

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

$ p4 submit -c 12346  # this will submit the changes to z.txt
$ p4 submit -c 12345  # this will submit the changes to a.txt

Я не могу понять, как это сделать в git. Из моих экспериментов не представляется, что git add связано с текущей ветвью. Насколько я могу судить, когда я git commit, он собирается передать все файлы, которые я git add -ed, независимо от того, в какой ветке я был в это время:

$ git init
Initialized empty Git repository in /home/laurence/git-playground/.git/
$ ls
a.txt  w.txt  z.txt
$ git add -A .
$ git commit
 Initial commit.
 3 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 a.txt
 create mode 100644 w.txt
 create mode 100644 z.txt
$ vi a.txt z.txt 
2 files to edit
$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   a.txt
#   modified:   z.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git branch aardvark
$ git checkout aardvark
M   a.txt
M   z.txt
Switched to branch 'aardvark'
$ git add a.txt 
$ git checkout master
M   a.txt
M   z.txt
Switched to branch 'master'
$ git branch zebra
$ git checkout zebra
M   a.txt
M   z.txt
Switched to branch 'zebra'
$ git add z.txt 
$ git status
# On branch zebra
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a.txt
#   modified:   z.txt
#
$ git checkout aardvark
M   a.txt
M   z.txt
Switched to branch 'aardvark'
$ git status
# On branch aardvark
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a.txt
#   modified:   z.txt

В этом примере ветки aardvark и zebra, похоже, содержат точно такой же набор изменений, и на основе вывода git status кажется, что выполнение фиксации в любом случае будет иметь тот же эффект. Я что-то делаю неправильно?

Ответ 1

Я не использовал perforce, так что это не может быть точно перевод 1:1. Затем снова распределенные системы управления источниками, такие как git и mercurial, имеют разные рабочие процессы, так что на самом деле нет (и не должно быть) перевода 1:1. В любом случае, здесь идет:

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

    git branch new-branch-name
    git checkout new-branch-name
    

    Или сделать все в одной строке:

    git checkout -b new-branch-name
    
  • См. список всех ожидающих списков изменений → Поскольку эквивалент нескольких ожидающих изменений списков изменений состоит из нескольких ветвей, просто просмотрите ветки:

    git branch
    

    Если вы также хотите просмотреть удаленные ветки:

    git branch -a
    

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

  • Список всех измененных файлов → Для одного ожидающего "списка изменений" в конкретной ветке git есть концепция индекса или кеша. Чтобы совершить изменение, вы должны сначала добавить файлы к этому индексу. Это позволяет вам вручную выбрать, какая группа файлов представляет собой одно изменение или игнорировать нерелевантные файлы. Чтобы узнать, какие файлы добавлены или нет, просто выполните этот индекс:

    git status
    
  • См. разницу ожидающего списка изменений → Есть две части этого. Сначала нужно увидеть разницу между рабочим каталогом и индексом:

    git diff
    

    Но если вы хотите узнать разницу между тем, что вы печатаете сейчас и последним, то вы действительно просите разницу между рабочим каталогом + индексом и HEAD:

    git diff HEAD
    
  • Для данного файла см., какие представленные списки изменений повлияли на то, какие строки → Это легко:

    git blame filename
    

    или даже лучше, если вы находитесь в среде окон:

    git gui blame filename
    

    Git gui занимает больше времени, чтобы проанализировать файл (он был написан в tcl вместо C), но он имеет множество опрятных функций, включая возможность "путешествовать во времени" обратно в прошлое, нажав на идентификатор фиксации. Я только хочу, чтобы они реализовали функцию "путешествия во времени" в будущее, чтобы я мог узнать, как окончательно решить данную ошибку; -)

  • Для данного файла см. список описаний списков изменений, которые повлияли на файл → также легко:

    git log filename
    

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

  • Отправить ожидающий список изменений → Также легко:

    git commit
    

См. мой ответ на предыдущий вопрос, чтобы увидеть мой типичный рабочий процесс git: Обучение Git. Нужно знать, если я на правильном пути

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


Дополнительный ответ:

Git очень гибкий, и есть несколько способов сделать то, что вы описываете. Следует помнить, что всегда нужно начинать новую ветку для каждой функции, над которой вы работаете. Это означает, что главная ветвь не тронута, поэтому вы всегда можете вернуться к ней, чтобы исправить ошибки. Работая в git, нужно почти всегда начинать с:

git checkout -b new-feature-a

Теперь вы можете отредактировать файл a.txt. Одновременно работать с другой функцией:

git checkout master
git checkout -b new-feature-z

Теперь вы можете редактировать файл z.txt. Чтобы вернуться к a.txt:

git checkout new-feature-a

Но подождите, есть изменения в new-feature-z, а git не позволит вам переключаться между ветвями. На данный момент у вас есть два варианта. Первый - самый простой, скопируйте все изменения в текущую ветку:

git add .
git commit
git checkout new-feature-a

Это то, что я бы рекомендовал. Но если вы действительно не готовы выполнить код, вы можете временно его сохранить:

git stash

Теперь вы можете переключиться на ветвь new-feature-a. Чтобы вернуться к коду, над которым вы работали, просто нажмите на значок:

git checkout new-feature-z
git stash pop

Когда все будет выполнено, слейте все изменения в master:

git merge --no-ff new-feature-a
git merge --no-ff new-feature-z

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

Вот еще один пример общего использования ветвей в git, который вы не видите в других инструментах управления версиями (кроме, быть может, меркуриальных):

Вам нужно постоянно менять конфигурационные файлы, чтобы они отражали вашу среду разработки? Затем используйте ветку:

git checkout -b dev-config

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

git add .
git commit

Теперь каждая новая ветка может начинаться с ветки dev-config вместо master:

git checkout dev-config
git checkout -b new-feature-branch

Как только вы закончите, удалите изменения в dev-config из ветки new-feature с помощью интерактивной rebase:

git rebase -i master

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

git checkout master
git merge --no-ff new-feature-branch
# because master have changed, it a good idea to rebase dev-config:
git checkout dev-config
git rebase master

Следует отметить, что удаление изменений с помощью git rebase -i даже работает, когда все изменения происходят в одном файле. git запоминает изменения, а не содержимое файла *.

* Примечание: на самом деле, технически не совсем верно, но как пользователь, что он чувствует себя


Дополнительный ответ:

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

Во-первых, слово о влиянии дешевой ветвящейся и модифицируемой истории на ваш рабочий процесс. Когда я использовал CVS и SVN, я всегда был немного неохотным. Это из-за того, что выполнение неустойчивого кода неизбежно f ** k над другим рабочим кодом. Но с git я потерял этот страх. Это потому, что в git другие люди не получат мои изменения, пока я не объединю их для освоения. Итак, теперь я нахожу, что делаю код каждые 5 строк, которые я пишу. Вам не нужно совершенное предвидение для совершения. Вам просто нужно изменить свое мышление: commit-to-branch == add-to-changeset, merge-to-master == commit-changeset.

Итак, вернемся к примерам. Вот как я это сделаю. Скажем, у вас есть ветвь new-feature-z, и вы хотите протестировать ее с помощью new-feature-a. Я бы просто создал новую ветку для тестирования:

# assume we are currently in branch new-feature-z
# branch off this branch for testing
git checkout -b feature-z-and-feature-a
# now temporarily merge new-feature-a
git merge --no-ff new-feature-a

Теперь вы можете проверить. Если вам нужно что-то изменить, чтобы сделать функцию-z работать с функцией-a, тогда сделайте это. Если это так, вы можете объединить изменения в соответствующую ветку. Используйте git rebase -i для удаления нерелевантных изменений из слияния.

В качестве альтернативы вы также можете использовать git rebase, чтобы временно изменить базу new-feature-z, чтобы указать на новую функцию-a:

# assume we are currently in branch new-feature-z
git rebase new-feature-a

Теперь история ветвей изменяется так, что new-feature-z будет основываться на new-feature-a вместо master. Теперь вы можете проверить. Любые изменения, совершенные в этой ветке, будут принадлежать ветке new-feature-z. Если вам нужно изменить новую функцию - просто вернитесь к ней и переформатируйте, чтобы получить новые изменения:

git checkout new-feature-a
# edit code, add, commit etc..
git checkout new-feature-z
git rebase new-feature-a
# now new-feature-z will contain new changes from new-feature-a

Когда вы закончите, просто переустановите мастер для удаления изменений из new-feature-a:

# assume we are currently in branch new-feature-z
git rebase master

Не бойтесь начать новую ветку. Не бойтесь начать отброшенную ветку. Не бойтесь выбросить ветки. И поскольку merge == submit и commit == add-to-changeset не боятся совершать часто. Помните, что commit - это инструмент отмены от разработчика.

О, и еще одна вещь, в git удаленные ветки все еще существуют в вашем репозитории. Поэтому, если вы случайно удалили то, что позже понимаете, полезно после всего, что вы всегда можете вернуть его, просмотрев историю. Так что не бойтесь выбросить ветки.

Ответ 2

У меня недостаточно опыта работы с p4, чтобы создать фактический чит-лист, но есть, по крайней мере, некоторое сходство. P4 "changeet" является git "commit".

Изменения в локальном рабочем пространстве добавляются в "индекс" с помощью git add, а индекс позже передается с помощью git commit. Таким образом, индекс является вашим ожидающим списком изменений для всех целей и целей.

Вы просматриваете изменения с помощью git diff и git status, где git diff обычно показывает изменения между рабочей областью и индексом, но git diff --cached показывает изменения между индексом и репозиторием (= ваш ожидающий список изменений).

Более подробную информацию я рекомендую http://progit.org/book/. Поскольку вы знаете управление версиями в целом, вы можете, вероятно, сэкономить много его и извлечь git -специальную информацию...

Ответ 3

Я страдаю, как вы, с отсутствием понятия "changelist", которое не совсем совпадает с ветвями git.

Я бы написал небольшой script, который создаст файл списка изменений со списком файлов в этом списке изменений.

Другая команда, чтобы отправить только определенный список изменений, просто набрав git commit -a @change_list_contents.txt, а затем "git commit"

Надеюсь, что это поможет, Элиас

Ответ 4

В git есть более легкая альтернатива, которая может стать частью вашего рабочего процесса; используя область git.

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

Вы можете передать определенные файлы из командной строки с помощью

git commit a.txt
git commit z.txt

Или сначала сначала создавайте файлы:

git add a.txt
git commit
git add z.txt
git commit

git gui позволит вам выбирать строки или куски из файлов для создания фиксации в промежуточной области. Это очень полезно, если у вас есть изменения в одном файле, который вы хотите использовать в разных записях. Переместившись из git в perforce, и это одна вещь, которую я действительно пропускаю.

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

Ответ 5

Это не отвечает на ваш вопрос конкретно, но я не знаю, знаете ли вы, что 2 пользователя, 5 Workspace версии perforce можно бесплатно скачать и использовать с perforce website.

Таким образом, вы можете использовать perforce дома для своих личных проектов, если хотите. Одно раздражение - это 5 рабочих пространств, которые могут быть немного ограниченными, но его довольно невероятно, чтобы иметь возможность использовать для домашнего использования.