Uso o Perforce há vários anos. Eu gostaria de passar a usar git para meu código pessoal, mas todos os tutoriais de git que eu vi presumem que você é um controle de fonte completo n00b (o que os torna incrivelmente tediosos) ou que você está acostumado svn (que eu não sou).
Eu conheço o p4, e também entendo a ideia por trás de um sistema de controle de origem distribuído (então não preciso de um discurso de vendas, obrigado). O que eu gostaria é uma tabela de tradução do comando p4 para comandos git equivalentes, bem como os comandos "não podem viver sem" que não têm equivalente p4.
Como suspeito que cada usuário p4 usa um subconjunto diferente de p4, aqui estão algumas das coisas que faço regularmente no p4 que gostaria de poder fazer no git e que não são imediatamente óbvias pelos documentos que li :
- crie várias changelists pendentes em um único cliente. (
p4 change
) - editar uma lista de alterações pendente. (também
p4 change
) - veja uma lista de todas as minhas changelists pendentes (
p4 changes -s pending
) - lista de todos os arquivos alterados em meu cliente (
p4 opened
) ou em uma lista de alterações pendente (p4 describe
) - veja um diff de uma changelist pendente (eu uso um script wrapper para isso que usa
p4 diff
ep4 describe
) - para um determinado arquivo, veja quais changelists enviadas afetaram quais linhas (
p4 annotate
) - para um determinado arquivo, veja uma lista das descrições das changelists que afetaram o arquivo (
p4 log
) - enviar uma changelist pendente (
p4 submit -c
) - abortar uma changelist pendente (
p4 revert
)
Muitos deles giram em torno de "changelists". "changelist" é a terminologia p4. Qual é o termo equivalente do git?
Parece que branches podem ser o que os usuários git usam no lugar do que o p4 chama de changelists. Um pouco confuso, já que p4 também tem algo chamado de branch, embora eles pareçam ser conceitos apenas vagamente relacionados. (Embora eu sempre tenha pensado que o conceito de ramificação do p4 era muito estranho, é diferente mais uma vez do conceito RCS clássico de ramificação.)
Enfim ... Não tenho certeza de como realizar o que normalmente faço em changelists p4 com branches do git. Em p4, posso fazer algo assim:
$ p4 edit a.txt
$ p4 change a.txt
Change 12345 created.
Neste ponto, tenho um changlist que contém a.txt. Posso editar a descrição e continuar trabalhando sem enviar a changelist. Além disso, se descobrir que preciso fazer algumas alterações em alguns outros arquivos, como, digamos, uma correção de bug em alguma outra camada do código, posso fazer isso no mesmo cliente:
$ p4 edit z.txt
$ p4 change z.txt
Change 12346 created.
Agora eu tenho duas changelists separadas no mesmo cliente. Posso trabalhar neles ao mesmo tempo e não preciso fazer nada para "alternar" entre eles. Quando chegar a hora de se comprometer, posso enviá-los separadamente:
$ p4 submit -c 12346 # this will submit the changes to z.txt
$ p4 submit -c 12345 # this will submit the changes to a.txt
Não consigo descobrir como replicar isso no git. Pelas minhas experiências, não parece que git add
está associado ao ramo atual. Pelo que eu posso dizer, quando git commit
vou comprometer todos os arquivos que eu fiz, git add
não importa em qual branch eu estava no momento:
$ 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
Neste exemplo, os ramos aardvark e zebra parecem conter exatamente o mesmo conjunto de alterações e, com base na saída git status
, parece que fazer um commit em qualquer um deles terá o mesmo efeito. Estou fazendo algo errado?
Respostas:
Não usei muito forçosamente, então esta pode não ser exatamente uma tradução 1: 1. Então, novamente, sistemas de controle de fonte distribuído como git e mercurial têm um fluxo de trabalho diferente, então realmente não há (e não deveria) haver uma tradução 1: 1. Enfim, aqui vai:
Crie várias changelists pendentes -> Use branches ao invés. No git, os branches são leves e rápidos, levam menos de um segundo para criar e normalmente menos de dois segundos para fundir. Não tenha medo de ramificar e rebase frequentemente.
Ou faça tudo em uma linha:
Veja uma lista de todas as changelists pendentes -> Como o equivalente a várias changelists pendentes são várias ramificações, basta visualizar as ramificações:
Se você deseja visualizar filiais remotas também:
É considerada uma boa prática excluir imediatamente um branch após uma mesclagem bem-sucedida, para que você não precise manter o controle de qual branch está pendente para ser mesclado e quais já foram mesclados.
Listar todos os arquivos alterados -> Para uma única "changelist" pendente em um branch específico, o git tem um conceito de índice ou cache. Para confirmar uma mudança, você deve primeiro adicionar arquivos a este índice. Isso permite selecionar manualmente qual grupo de arquivos representa uma única alteração ou ignorar arquivos irrelevantes. Para ver o status de quais arquivos são adicionados ou não a este índice, basta fazer:
Veja uma diferença de uma lista de mudanças pendente -> Existem duas partes para isso. Primeiro, para ver uma diferença entre o diretório de trabalho e o índice:
Mas se você quiser saber a diferença entre o que você está digitando agora e o último commit, então você está realmente pedindo uma diferença entre o diretório de trabalho + índice e o HEAD:
Para um determinado arquivo, veja quais changelists enviadas afetaram quais linhas -> Isso é fácil:
ou melhor ainda, se você estiver em um ambiente com janelas:
Git gui leva mais tempo para analisar o arquivo (foi escrito em tcl em vez de C), mas tem muitos recursos interessantes, incluindo a capacidade de "viajar no tempo" de volta ao passado clicando em um ID de confirmação. Eu só gostaria que eles implementassem um recurso de "viagem no tempo" para o futuro para que eu pudesse descobrir como um determinado bug será finalmente resolvido ;-)
Para um determinado arquivo, veja uma lista das descrições das changelists que afetaram o arquivo -> também fácil:
Mas o git log é uma ferramenta muito mais poderosa do que apenas isso. Na verdade, a maioria dos meus scripts pessoais usa o log do git para ler o repositório. Leia a página do manual.
Envie uma lista de alterações pendente -> Também é fácil:
Veja minha resposta a uma pergunta anterior para ver meu fluxo de trabalho típico do git: Aprendendo Git. Preciso saber se estou no caminho certo
Se você seguir o fluxo de trabalho que descrevi, verá que ferramentas como o gitk são muito mais valiosas, pois permitem ver claramente grupos de mudanças.
Resposta adicional:
Git é muito flexível e há várias maneiras de fazer o que você descreve. A coisa a lembrar é sempre iniciar um novo branch para cada recurso que você está trabalhando. Isso significa que o branch master não é tocado, então você sempre pode voltar a ele para fazer correções de bugs. Trabalhando no git, deve-se quase sempre começar com:
Agora você pode editar o arquivo a.txt. Para trabalhar simultaneamente em outro recurso, faça:
Agora você pode editar o arquivo z.txt. Para voltar a a.txt:
Mas espere, há mudanças em new-feature-z e git não permitirá que você troque de branch. Neste ponto, você tem duas opções. O primeiro é o mais simples, comprometa todas as alterações no branch atual:
Isso é o que eu recomendo. Mas se você realmente não está pronto para confirmar o código, pode armazená-lo temporariamente:
Agora você pode mudar para o branch new-feature-a. Para voltar ao código em que você estava trabalhando, basta abrir o estoque:
Quando tudo estiver pronto, reúna todas as alterações no mestre:
Como as fusões são tão rápidas e fáceis (fáceis porque os conflitos são tão raros e a resolução de conflitos, quando uma acontece, não é muito difícil), usamos branches no git para tudo.
Aqui está outro exemplo de uso comum de branches no git que você não vê em outras ferramentas de controle de origem (exceto talvez mercurial):
Precisa ficar mudando seus arquivos de configuração para refletir seu ambiente de desenvolvimento? Então use um branch:
Agora edite seus arquivos de configuração em seu editor favorito e submeta as alterações:
Agora, cada novo branch pode começar do branch dev-config em vez do master:
Assim que terminar, remova as edições em dev-config de new-feature-branch usando rebase interativo:
Exclua os commits que você não deseja e salve. Agora você tem um branch limpo sem edições de configuração personalizadas. É hora de voltar ao master:
Deve-se observar que a remoção das edições com
git rebase -i
even funciona quando todas as alterações acontecem no mesmo arquivo. Git se lembra das mudanças, não do conteúdo do arquivo *.* nota: na verdade, tecnicamente não é totalmente verdade, mas como usuário é assim que parece
Mais respostas adicionais:
Portanto, a partir de seus comentários, parece que você deseja que duas ramificações existam simultaneamente para que possa testar como o código combinado funciona. Bem, esta é uma boa maneira de ilustrar o poder e a flexibilidade das ramificações.
Primeiro, uma palavra sobre a implicação de ramificações baratas e histórico modificável em seu fluxo de trabalho. Quando eu estava usando CVS e SVN, sempre fui um pouco relutante em comprometer. Isso porque comprometer código instável inevitavelmente estragaria o código de trabalho de outras pessoas. Mas com o git perdi esse medo. Isso porque no git outras pessoas não receberão minhas alterações até que eu as mescle com o master. Então agora eu me vejo comprometendo código a cada 5 linhas que escrevo. Você não precisa de uma previsão perfeita para se comprometer. Você só precisa mudar sua mentalidade: commit-to-branch == add-to-changeset, merge-to-master == commit-changeset.
Então, de volta aos exemplos. É assim que eu faria. Digamos que você tenha um branch
new-feature-z
e queira testá-lonew-feature-a
. Gostaria apenas de criar um novo branch para testá-lo:Agora você pode testar. Se você precisar modificar algo para fazer o recurso-z funcionar com o recurso-a, faça isso. Nesse caso, você pode mesclar novamente as alterações para o branch relevante. Use
git rebase -i
para remover alterações irrelevantes da fusão.Como alternativa, você também pode usar git rebase para alterar temporariamente a base de new-feature-z para apontar para new-feature-a:
Agora, o histórico de ramificações foi modificado para que new-feature-z seja baseado em new-feature-a em vez de master. Agora você pode testar. Quaisquer alterações confirmadas neste branch pertencerão ao branch new-feature-z. Se você precisar modificar new-feature-a, basta voltar para ele e fazer o rebase para obter as novas alterações:
Quando terminar, basta fazer o rebase de volta ao master para remover as alterações do new-feature-a:
Não tenha medo de iniciar um novo ramo. Não tenha medo de iniciar um galho descartável. Não tenha medo de jogar fora galhos. E como mesclar == enviar e confirmar == add-to-changeset, não tenha medo de fazer commit com frequência. Lembre-se de que o commit é a ferramenta de desfazer definitiva do desenvolvedor.
Ah, e outra coisa, no git, branches excluídos ainda existem em seu repositório. Portanto, se você acidentalmente excluiu algo que mais tarde percebe que é útil, você sempre pode recuperá-lo pesquisando no histórico. Portanto, não tenha medo de jogar fora os galhos.
fonte
Não tenho experiência suficiente em p4 para produzir uma folha de cola real, mas existem pelo menos algumas semelhanças nas quais recorrer. Um "changeset" p4 é um "commit" git.
As alterações em seu espaço de trabalho local são adicionadas ao "índice" com
git add
, e o índice posteriormente é confirmado comgit commit
. Portanto, o índice é sua lista de alterações pendente, para todos os efeitos.Você olha as mudanças com
git diff
egit status
, ondegit diff
geralmente mostra as mudanças entre o espaço de trabalho e o índice, masgit diff --cached
mostra as mudanças entre o índice e o repositório (= sua lista de mudanças pendente).Para obter informações mais detalhadas, recomendo http://progit.org/book/ . Já que você conhece o controle de versão em geral, você provavelmente pode folhear muito dele e extrair as informações específicas do git ...
fonte
Eu sofro como você com a falta do conceito de "changelist", que não é exatamente o mesmo que git branches.
Gostaria de escrever um pequeno script que criará um arquivo de lista de mudanças com a lista de arquivos dessa lista de mudanças.
Outro comando para enviar apenas uma determinada lista de mudanças simplesmente chamando git commit -a @ change_list_contents.txt e então "git commit"
Espero que ajude Elias
fonte
Existe uma alternativa mais leve no git que pode fazer parte do seu fluxo de trabalho; usando a área de teste do git.
Freqüentemente, apenas faço alterações e, em seguida, envio como vários commits (por exemplo, adicionar instruções de depuração, refatorar, corrigir um bug). Em vez de configurar suas changelists forçadas, fazer alterações e enviar, você pode apenas fazer suas alterações e escolher como enviá-las (opcionalmente usando a área de teste do git).
Você pode confirmar arquivos específicos da linha de comando com:
Ou testando explicitamente os arquivos primeiro:
git gui permitirá que você selecione linhas ou pedaços de dentro dos arquivos para construir um commit na área de teste. Isso é muito útil se você tiver alterações em um arquivo que deseja colocar em commits diferentes. Ter mudado do git para o forçado e isso é uma coisa que eu realmente sinto falta.
Há uma pequena ressalva a ser considerada com esse fluxo de trabalho. Se você fizer alterações A e B em um arquivo, teste o arquivo e, em seguida, envie A, então você não testou esse commit (independentemente de B).
fonte
Isso não responde a sua pergunta especificamente, mas não sei se você está ciente de que uma versão 2 usuários e 5 espaços de trabalho do perforce é gratuita para baixar e usar do site do perforce .
Desta forma, você pode usar forçosamente em casa para seus projetos pessoais, se desejar. O único incômodo são os 5 espaços de trabalho que podem ser um pouco limitantes, mas é incrível ter forçosamente disponíveis para uso doméstico.
fonte
Tendo usado Perforce e git de forma bastante extensa, só há uma maneira que posso ver de chegar perto de changelists do Perforce com git.
A primeira coisa a entender é que para implementar corretamente essa funcionalidade no git de uma forma que não seja um kluge completo, por exemplo, tentar calçá-lo em branches, exigiria a seguinte mudança: git exigiria várias áreas de teste para um único branch .
As changelists do Perforce permitem um fluxo de trabalho que simplesmente não tem equivalente no git. Considere o seguinte fluxo de trabalho:
Se você tentar fazer isso usando branches no git, você acabará com dois branches, um dos quais tem as mudanças no arquivo
A
, o outro tem as mudanças no arquivoB
, mas nenhum lugar onde você possa ver as mudanças em ambos os arquivosA
eB
em o mesmo tempo.A aproximação mais próxima que posso ver é usar
git add . -p
e, em seguida, usar o'a'
e'd'
sub-comandos para selecionar ou rejeitar arquivos inteiros. No entanto, isso não é exatamente o mesmo, e a diferença aqui decorre de uma disparidade fundamental no modus operandi geral dos dois sistemas.Git (e subversion, não que isso importe para esta discussão) permite que um arquivo seja alterado sem avisar ninguém sobre isso com antecedência. Você apenas altera um arquivo, e então deixa o git resolver tudo quando você efetua o commit das alterações. O Perforce exige que você verifique ativamente um arquivo antes que as alterações sejam permitidas, e é por esta razão que as changelists devem existir. Em essência, o Perforce requer que você adicione um arquivo ao índice antes de alterá-lo. Daí a necessidade de múltiplas changelists no Perforce, e também a razão pela qual git não tem equivalente. Simplesmente não precisa deles.
fonte
Com Git 2.27 (Q2 2020), "
git p4
" aprendeu quatro novos ganchos e também "--no-verify
" a opção de contorná-los (e o "p4-pre-submit
" gancho existente ).Consulte commit 1ec4a0a , commit 38ecf75 , commit cd1e0dc (14 de fevereiro de 2020) e commit 4935c45 , commit aa8b766 , commit 9f59ca4 , commit 6b602a2 (11 de fevereiro de 2020) por Ben Keene (
seraphire
) .(Fundido por Junio C Hamano -
gitster
- no commit 5f2ec21 , 22 de abril de 2020)Antes do Git 2.28 (Q3 2020), a
--prepare-p4-only
opção " " deveria parar após repetir um changeset, mas continuava (por engano?)Veja o commit 2dfdd70 (12 de maio de 2020) de Ben Keene (
seraphire
) .(Fundido por Junio C Hamano -
gitster
- no commit 7a8fec9 , 02 Jun 2020)fonte