Quando um controle de versão é muito grande? [fechadas]


65

Já ouvi em vários lugares "Não faça grandes confirmações", mas nunca entendi o que é uma confirmação "grande". É grande se você trabalhar em um monte de arquivos, mesmo que haja algum relacionado? Em quantas partes de um projeto você deve trabalhar ao mesmo tempo?

Para mim, tenho problemas para tentar fazer "pequenas confirmações", pois esqueço ou crio algo que cria outra coisa que cria outra coisa. Você acaba com coisas assim:

Fila de saída personalizada criada

Robô
-Novo campo msgQueue, que nada mais é que um SingleThreadExecutor
-sendMsg bloqueia até que a mensagem seja enviada e adiciona espera entre quando as mensagens são recebidas
enviei
Chamadas -adminExist atualizadas (consulte o controlador)
- Chamadas removidas para sendMessage

Controlador
-Novo campo msgWait indica tempo de espera entre mensagens
-Iniciar os plug-ins de serviço movidos para reloadPlugins
-adminExists mudou do servidor por causa de administradores globais. Cheques no canal,
servidor e nível global

Admin
-New métodos getServer e getChannel que obtêm o objeto apropriado Admin
pertence a

BotEvent
-toString () também mostra extra e extra1 do show

Canal
-channel renomeado para nome
- Erro de digitação corrigido no canal (int)

Servidor
-Moved adminExists to Controller

PluginExecutor
- Pequenos testes adicionados, serão removidos mais tarde

JS Plugins
-Atualizado para mudanças na estrutura
Substituído InstanceTracker.getController () com Controller.instance
-VLC conversa agora em arquivo próprio

Várias atualizações e alterações do projeto NB

---

Arquivos afetados
Modifique /trunk/Quackbot-Core/dist/Quackbot-Core.jar
Modifique /trunk/Quackbot-Core/dist/README.TXT
Modifique /trunk/Quackbot-Core/nbproject/private/private.properties
Modifique /trunk/Quackbot-Core/nbproject/private/private.xml
Modifique /trunk/Quackbot-Core/src/Quackbot/Bot.java
Modifique /trunk/Quackbot-Core/src/Quackbot/Controller.java
Modifique /trunk/Quackbot-Core/src/Quackbot/PluginExecutor.java
Modifique /trunk/Quackbot-Core/src/Quackbot/info/Admin.java
Modifique /trunk/Quackbot-Core/src/Quackbot/info/BotEvent.java
Modifique /trunk/Quackbot-Core/src/Quackbot/info/Channel.java
Modifique /trunk/Quackbot-Core/src/Quackbot/info/Server.java
Modifique /trunk/Quackbot-GUI/dist/Quackbot-GUI.jar
Modifique /trunk/Quackbot-GUI/dist/README.TXT
Modifique /trunk/Quackbot-GUI/dist/lib/Quackbot-Core.jar
Modifique /trunk/Quackbot-GUI/nbproject/private/private.properties
Modifique /trunk/Quackbot-GUI/nbproject/private/private.xml
Modifique /trunk/Quackbot-GUI/src/Quackbot/GUI.java
Modifique /trunk/Quackbot-GUI/src/Quackbot/log/ControlAppender.java
Excluir /trunk/Quackbot-GUI/src/Quackbot/log/WriteOutput.java
Modifique /trunk/Quackbot-Impl/dist/Quackbot-Impl.jar
Modifique /trunk/Quackbot-Impl/dist/README.TXT
Modifique /trunk/Quackbot-Impl/dist/lib/Quackbot-Core.jar
Modifique /trunk/Quackbot-Impl/dist/lib/Quackbot-GUI.jar
Modifique /trunk/Quackbot-Impl/dist/lib/Quackbot-Plugins.jar
Modifique /trunk/Quackbot-Impl/lib/javarebel.stats
Adicione /trunk/Quackbot-Impl/lib/jrebel.info
Modifique /trunk/Quackbot-Impl/nbproject/private/private.properties
Modifique /trunk/Quackbot-Impl/nbproject/private/private.xml
Modifique /trunk/Quackbot-Impl/nbproject/project.properties
Modifique /trunk/Quackbot-Impl/plugins/CMDs/Admin/reload.js
Adicione / trunk / Quackbot-Impl / plugins / CMDs / Operator / hostBan
Modifique /trunk/Quackbot-Impl/plugins/CMDs/Operator/mute.js
Modifique /trunk/Quackbot-Impl/plugins/CMDs/lyokofreak/curPlaying.js
Modifique /trunk/Quackbot-Impl/plugins/CMDs/lyokofreak/lfautomode.js
Modifique /trunk/Quackbot-Impl/plugins/listeners/onJoin.js
Modifique /trunk/Quackbot-Impl/plugins/listeners/onQuit.js
Modifique /trunk/Quackbot-Impl/plugins/testCase.js
Adicione /trunk/Quackbot-Impl/plugins/utils/whatsPlaying.js
Modifique /trunk/Quackbot-Impl/src/Quackbot/impl/SandBox.java
Adicione / trunk / Quackbot-Impl / vlc_http
Adicione /trunk/Quackbot-Impl/vlc_http/current.html
Modifique /trunk/Quackbot-Plugins/dist/Quackbot-Plugins.jar
Modifique /trunk/Quackbot-Plugins/dist/README.TXT
Modifique /trunk/Quackbot-Plugins/dist/lib/Quackbot-Core.jar
Modifique /trunk/Quackbot-Plugins/nbproject/private/private.properties
Modifique /trunk/Quackbot-Plugins/nbproject/private/private.xml
Modifique /trunk/Quackbot-Plugins/src/Quackbot/plugins/JSPlugin.java
Adicione / trunk / Quackbot-Plugins / vlc_http
Adicione /trunk/global-lib/jrebel.jar

Sim....

Então, para perguntas:

  • Quais são alguns fatores para quando um commit se torna muito grande ( coisas não óbvias )?
  • Como você pode impedir tais confirmações? Por favor, especifique
  • E quando você está nos estágios semi-iniciais do desenvolvimento, quando as coisas estão se movendo rapidamente? Confirmações enormes ainda estão bem?

lists.madduck.net/pipermail/vcs-home/2010-September/000276.html descreve um caso em que os próprios arquivos de dados são grandes demais para serem efetivamente armazenados no repositório. (Mas eu tenho certeza que não é o que estamos falando aqui.)
Ken Bloom

Não construtivo ????? Acabei de aprender uma tonelada aqui! Mods, por favor, pare de fechar sua pergunta draconiana!
Richard

O que você nunca viu um único commit com centenas de arquivos, que qualquer parte dele não compilaria?
Joshua

Respostas:


67

Para mim, tenho problemas para tentar fazer "pequenas confirmações", pois esqueço ou crio algo que cria outra coisa que cria outra coisa.

Isso é um problema. Parece que você precisa aprender a dividir seu trabalho em pedaços menores e mais gerenciáveis.

O problema com confirmações grandes são:

  • Em um projeto para várias pessoas, uma maior chance de seus commits causarem conflitos para outros desenvolvedores resolverem.
  • É mais difícil descrever com precisão o que foi feito nas mensagens de log.
  • É mais difícil rastrear a ordem em que as alterações foram feitas e, portanto, entender a causa dos problemas.
  • Aumenta a probabilidade de perder muito trabalho não comprometido.

Às vezes, grandes confirmações são inevitáveis; por exemplo, se você precisar alterar uma API principal. Mas isso normalmente não é o caso. E se você se encontra nessa situação, provavelmente é uma boa idéia criar um ramo e fazer seu trabalho lá ... com muitos pequenos commits ... e se reintegrar quando terminar.

(Outro caso é quando você faz uma importação inicial, mas isso NÃO é problemático da perspectiva dos problemas listados acima.)


7
+1, definitivamente aprenda como dividi-lo em pedaços menores. Ao procurar um bug, confirmações menores são mais fáceis de gerenciar. Após as primeiras vezes em que você observa um commit grande, você terá o hábito: P
dr Hannibal Lecter

2
Se necessário, no final da série de pequenas confirmações, você pode adicionar um rótulo / etiqueta que inclua uma descrição resumida longa. Isso aplica efetivamente uma linha de base no ponto em que seu grande bloco de trabalho é realizado, antes de você se reintegrar ou iniciar alguma forma de teste mais formal (isso deve fazer parte de como você / sua empresa trabalha). EU ADICIONARIA: Fazer mudanças em grande escala (como você sugere) em um ramo de desenvolvimento é uma ideia extremamente boa. Evita a poluição do seu fluxo principal com grandes montes de lixo e facilita a criação de service packs de correção rápida, etc., se necessário.
precisa saber é o seguinte

11
Além disso, commits menores = diffs menores para pessoas que revisam PRs commit-by-commit
peter

40

O princípio da responsabilidade única.

Toda confirmação de controle de origem deve servir apenas a um propósito. Se você precisar colocar a palavra "e" ou "também" em seu resumo, precisará dividi-la.

É muito comum acabar com muitas alterações independentes ou semid relacionadas na sua cópia de trabalho. Isso é chamado de "problema de cópia de trabalho emaranhada" e é realmente muito difícil de evitar, mesmo para desenvolvedores disciplinados. No entanto, o Git e o Mercurial oferecem ferramentas para resolvê-lo - git add -p ou chunk selection e Mercurial Queues no TortoiseHg, respectivamente.


2
esse é um bom princípio; no entanto, na prática, eu ainda aceitaria confirmações que fazem várias coisas (especialmente se estiverem relacionadas) e se o tamanho da confirmação for pequeno o suficiente; Para compensar, recomendo que você seja um mestre em rebase interativa para reescrever o histórico não enviado até que seja bom e claro.
Rivenfall

26

Imagine que o cliente pediu para fazer uma alteração específica - por exemplo, para adicionar uma regra de que algo ou outro não pode ser feito dentro de dois dias da data "qualquer que seja". Depois que você fez a alteração, eles mudam de idéia. Você desejará reverter seu commit. Se tudo está misturado com algumas coisas sobre como alterar a ordem de classificação de relatórios não relacionados, sua vida é uma miséria.

Um item de trabalho, um changeset. Um pedido do cliente, um changeset. Uma coisa sobre a qual você pode mudar de idéia é uma mudança. Às vezes, isso significa que é uma única linha de código. Às vezes, são dez arquivos diferentes, incluindo o esquema do banco de dados. Isso é bom.


Concordo completamente com os "1 linha / 10 arquivos". Lá muitas variáveis para responder a esta pergunta de um conjunto padrão de leis
Pulak Agrawal

7
A única coisa que eu acrescentaria é que, às vezes, faz sentido ficar ainda menor do que "uma solicitação, uma alteração". Solicitações maiores devem ser divididas em conjuntos de alterações incrementais menores. (Como mencionado em outra resposta, o desenvolvimento em uma ramificação pode facilitar isso). Por fim, posso adaptar o mantra mencionado acima: "Uma solicitação, um (ou mais!) Conjuntos de alterações".
Rinogo

10

Confirmações grandes são quando você tem toneladas de alterações que nem sempre estão no mesmo balde. Se eu mudar a lógica do controlador, o modelo de conexão com o banco de dados e alguns outros. scripts, eu não deveria agrupar tudo em um commit.

Prevenção é fazer confirmações de acordo com o que você está concluindo. No exemplo acima, eu confirmaria após a lógica do controlador, após o trabalho do banco de dados e após os scripts. Não adie cometer simplesmente porque você sabe o que mudou. Outras pessoas analisarão sua mensagem de log de confirmação de "Coisas alteradas" e se perguntarão o que você estava fumando.

As importações iniciais são provavelmente as maiores confirmações que você já deve ter. Configurando um sistema a partir do zero? Claro que tem alguns grandes commits. Depois de nivelá-lo, é hora de manter as coisas organizadas.


7

Se você sabe que vai trabalhar com um grande pedaço de código de antemão, sugiro que você crie um ramo para seu recurso específico, enquanto extrai periodicamente o código da linha principal para garantir que seu código permaneça sincronizado. Quando você terminar de trabalhar na ramificação, mesclar todas as suas alterações novamente na linha principal. Dessa forma, outros membros da equipe não ficarão surpresos e / ou aborrecidos quando virem um grande comprometimento. Além disso, há muito menos chance de quebrar as coisas. Continue praticando para dividir as coisas em commits menores. Com o tempo, isso se tornará uma segunda natureza.


7

Este exemplo mostra um commit muito grande.

Como regra geral, descreva a alteração em uma frase ou em uma linha de texto. (Com base nessa regra, o commit deve ser dividido em 10 a 15 menores.) Se você não puder comentar adequadamente um commit em uma linha, ele já será muito grande.

Para praticar confirmações menores, faça anotações no seu bloco de notas (ou no Bloco de Notas) do que você já mudou ou adicionou. Confirme antes que se torne uma lista longa ou antes de fazer uma alteração no código não relacionada ao que você já possui no bloco de notas.


O repositório de kernel do Linux tem muitos bons exemplos de violação dessa regra - eles geralmente têm muitas explicações sobre a causa do bug ou a justificativa para a correção no corpo da mensagem de confirmação. Uma versão razoável de sua regra seria "você deve sempre ser capaz de explicar o ponto principal de um commit em uma frase".
Ken Bloom

@ Ken: meu objetivo aqui é ajudar a pessoa que faz a pergunta, a não criar uma regra que cubra todos os repositórios de código-fonte pré-existentes no mundo.
Azheglov 11/11/10

6

No meu campo (modelagem física), descubro hoje um erro na saída que não estava no repositório há 6 meses. Quando isso acontecer, farei uma pesquisa binária nas revisões:

  1. Executar modelo de 3 meses atrás
  2. Se o erro ainda estiver em produção, execute o modelo de 4,5 meses atrás
  3. ... repita até encontrar o commit que gera uma saída ruim

Quando o bug foi introduzido em um cometimento monstruoso, tenho que me sentar com um pente fino para encontrar a fonte do problema. Se o commit tocou em um pequeno número de arquivos, é menos doloroso rastrear as linhas de código que introduziram o problema.

Eu recomendaria dividir seu problema em uma série de tarefas menores (idealmente, coloque cada tarefa em um rastreador de erros). Faça uma confirmação ao concluir cada tarefa (e feche esse bug / recurso no seu rastreador de erros).


Meses entre commits soar exatamente como commits maciços na maioria das metodologias modernas ...
Rig

5

Não é o tamanho do commit que realmente importa, é o escopo da mudança que deve determinar como seus compromissos são organizados.

Você pode, por exemplo, alterar todas as instâncias de __macro1para __macro2em uma grande base de códigos, que altera 200 arquivos. 200 compromissos não seriam sãos nesse caso.

O que você quer terminar é poder extrair o repositório com uma única revisão e fazer com que a construção funcione. Você mudou delibfoo para libbar? Espero que essa mudança inclua a atualização de seus scripts de compilação e Makefiles (ou o que for aplicável).

Às vezes, pode ser necessário fazer uma série de alterações experimentais que realizam uma coisa; nesse caso, você precisa determinar qual escopo é mais importante para você, se precisar reverter mais tarde. Um depende do outro? Confirme todos de uma vez em uma única revisão. Caso contrário, nesse caso, sugiro um commit por alteração. Você deve fazer algo assim em outro ramo ou em outro repositório de qualquer maneira.

Embora sim, você tem o poder de reverter um único arquivo para uma revisão anterior (o que faz com que um arquivo seja retirado de um compromisso maior). Isso faz com que você realmente estrague ferramentas como a bissecção mais tarde no caminho e polua a história.

Se você parar e pensar "Ok, os testes são aprovados, acho que isso funciona .. mas se der errado, posso voltar com facilidade?" .. você vai acabar fazendo compromissos sensatos.


4

O que devemos entender aqui é que "Grande", neste contexto, é sobre o número de alterações distintas, não o tamanho físico do commit (embora geralmente os dois andem de mãos dadas).

Não é uma questão de "não faça grandes commits", como fazem fazer pequenas commits - o ideal sendo a cometer pequena auto-contido mudanças.

Está claro pelo changelog que você tem uma série de coisas que poderiam ter sido cometidas separadamente (e com segurança) e, portanto, é bastante evidente que é muito grande.

A razão pela qual isso pode ser um problema é que o seu último commit é o seu ponto de referência para as alterações que você está fazendo no momento. Se, por exemplo, você acertar o primeiro bit e errar o próximo, não será fácil. para reverter o seu trabalho até o ponto em que você começou a cometer erros (BTDTGTTS).

É claro que às vezes as mudanças são grandes - refatoração em larga escala - e como sugerido por outras pessoas, é aqui que você precisa se ramificar, dessa maneira, embora o seu comprometimento individual possa interromper as coisas que são separadas do tronco principal de desenvolvimento. problema e você começa a se comprometer cedo e com frequência.

Mais uma coisa - se algo aparecer no meio do seu trabalho que requer atenção mais imediata, você precisará alterá-lo separadamente (idealmente em um conjunto de pastas completamente distinto) e enviá-lo separadamente.

O verdadeiro desafio de tudo isso não é a mecânica, é a mentalidade - que um commit não é apenas uma cópia de backup que você faz de vez em quando, mas que cada commit é um pedregulho ao longo do caminho e que não há nada errado com muitos de pequenos commits e que juntar coisas diferentes em um commit da multidão é tão ruim quanto juntar bits de funcionalidade vagamente relacionados em um pedaço de código.


4

No mínimo, treine-se para se comprometer sempre que pensar "gosto do meu progresso até agora e não quero perdê-lo se as mudanças que estou prestes a fazer forem um desastre". Então você tem a opção de aproveitar o VCS para eliminar quaisquer becos sem saída que você tentou ou código de depuração especial que você adicionou para rastrear um problema. (por exemplo, com git reset --hardou rm -rf *; svn update)


2

Não existe uma regra rígida e rápida, nenhuma linha divisória além da qual o seu commit é muito grande.

Não é no entanto uma orientação que as submissões menores são melhores, a razão (ou seja, comprometendo cada linha é probaby excessiva).

Eu mantenho esses tipos de diretrizes em mente:

  • Uma única confirmação deve incluir alterações para apenas uma correção de bug
  • Um único commit não deve incluir mais de meio dia de trabalho
  • Um único commit não deve interromper a construção

Claro - é isso que eu tenho em mente - YMMV. Diferentes desenvolvedores favorecem diferentes níveis de granularidade.


1

Quanto menor o commit, mais fácil será encontrar exatamente de onde vem uma regressão em potencial.

Idealmente, um commit deve ser atômico , no sentido da menor alteração coerente na base de código (relacionada a um bug, recurso, etc.).

Quanto às dicas específicas para manter pequeno o tamanho da confirmação, isso depende muito do seu VCS e de como está configurado: você deve poder confirmar localmente ou trabalhar em sua própria filial no servidor.

A chave é se comprometer com sua ramificação "privada" toda vez que você fizer uma alteração atômica e, em seguida, você poderá mesclar regularmente sua ramificação, por exemplo, toda semana.

Usando um dvcs, seu fluxo de trabalho pode ser assim:

code code code
git commit       // create commit locally with meaningful message
code code code
git commit       // create commit locally with meaningful message
code code code
git commit       // create commit locally with meaningful message
...
git push         // push your previous commits to the team server

Usando um vcs centralizado:

svn copy trunk my_feature_branch  // create your private branch
svn co my_private_branch          //
code code code
svn commit                        // commit on your private branch with meaningful comment
code code code
svn commit                        // commit on your private branch with meaningful comment
code code code
svn commit                        // commit on your private branch with meaningful comment
...
svn merge my_feature_branch trunk  // all your previous commit are merged to main/master branch

0

Você provavelmente já ouviu o ditado de que perfeição é quando você não pode tirar nada mais. Isso também deve descrever seu padrão para o tamanho da confirmação.

Depende do seu projeto onde está o tamanho "perfeito". Se você estiver enviando para clientes externos, um bom tamanho pode ser o menor incremento que seria confortável se não terminasse o próximo a tempo. Se você estiver criando aplicativos internos implantados com frequência, o melhor tamanho pode ser o menor incremento que não quebra nada (e aproxima você de onde você deseja estar).

Os sistemas modernos de controle de versão ajudam a criar boas confirmações com ramificação fácil, rebaseamento interativo, área de preparação, etc.


0

As mensagens de confirmação devem ter apenas uma linha (e para o git max 60 caracteres). A quantidade de código que está sendo confirmada deve ser pequena o suficiente para manter a mensagem descritiva dentro desse limite.

Eu costumo me comprometer toda vez (ainda mais agora que mudamos para o git). Eu tenho um pedaço pronto, pois permite capturar o "por que" as coisas foram feitas dessa maneira.


Isso parece um pouco, extremo. Um commit deve dizer o que você corrigiu e o que mudou. Dessa forma, você pode encontrar um commit com comportamento inadequado se algo quebrar e provar que você corrigiu algo.
TheLQ 10/10

@TheLQ: Novamente, trago como exemplo muitos dos commits no kernel Linux, onde uma longa mensagem de commit serve para comunicar a lógica de uma alteração específica a outros desenvolvedores.
Ken Bloom

@TheLQ, é assim que as coisas funcionam bem para nós. Lembre-se, você precisa ter o "porquê" em algum lugar ...

0

Às vezes, você trabalha o dia todo em vários nomes logicamente distintos e se esquece de confirmar seu código no meio. O uso git citoolpode ser muito útil para dividir seu trabalho em bons pedaços pequenos no final do dia, mesmo que você não tenha sido tão cuidadoso durante o dia enquanto estava trabalhando.

git citool pode permitir que você selecione quais blocos específicos de um arquivo (ou linhas específicas) a serem confirmadas em uma confirmação específica, para que você possa dividir as alterações (sem sobreposição) feitas no mesmo arquivo em várias confirmações.

(Parece que você usa o Subversion. Não conheço uma ferramenta que faça isso no Subversion, mas você pode usar git-svno adaptador Subversion para git, que mudará sua vida.)


Sim, essa é uma das coisas que sinto falta do git: a capacidade de confirmar apenas parte de um arquivo. Acho que, no final, seria uma bagunça, já que eu comprometeria 1 método, mas não o novo do qual depende, quebrando alguma coisa.
TheLQ

@TheLQ: bem, é isso que você deve fazer se quiser organizar seus commits em partes lógicas: ou seja muito disciplinado em cometer cedo e com frequência (e não tenha medo git rebasede ingressar em commits que realmente fazem parte do mesmo revisão) OU aprenda a seguir git citoolcom precisão um pente fino para dividir as coisas em partes lógicas quando estiver pronto para cometer no final do dia.
Ken Bloom

0

Quanto maior o commit, maior a probabilidade de você quebrar a compilação e ser pago pelo resto da sua equipe. Eu tento confirmar alterações duas vezes por dia. Pouco antes do almoço e antes de eu ir para casa. Então, às 12h e às 16h30, tento fazer tudo funcionar e pronto para confirmar. Acho que essa prática funciona para mim.


0

Para responder suas perguntas:

1) Para mim, o commit padrão é considerado grande se estiver fazendo mais de uma coisa. Por isso, quero dizer corrigir um bug ou adicionar um recurso.

2) Impedir tais confirmações, tornando um hábito e uma regra se comprometer sempre que você terminar algo.

3) Nos estágios semi-iniciais do desenvolvimento, permito que os commits incluam a primeira criação dos arquivos que serão usados ​​posteriormente.

Gostaria de observar que, ao terminar, quero dizer que todos os bugs que você pode identificar foram corrigidos e você não quebrará a compilação ao cometer.

Sim, isso gera um grande número de confirmações, mas permite reverter exatamente o que quebrou as coisas, em vez de ter que reverter uma grande série de alterações que foram confirmadas ao mesmo tempo em que apenas uma das alterações está causando um problema.

Eu também gostaria de salientar que as regras mudam um pouco para os sistemas de controle de versão distribuído (DVCS) como Mercurial e Git. No caso de você estar usando um desses, você confirma sempre que faz uma alteração, mas ainda não a testou e depois envia para o repositório central quando está funcionando. É preferível, pois permite revisar mais alterações no seu código sem se preocupar em interromper a compilação.


0

No meu caso, estou tentando confirmar arquivos de um servidor no sistema de repositório (SVN). Esse é o commit inicial e não deseja baixá-lo, pois é um projeto muito grande (alguns GB) e eu quero fazer o commit inicial no servidor do cliente.

O problema é que o cliente está em um servidor compartilhado, o cliente svn é morto (ou qualquer outro software) se for executado mais de um minuto.

Uma alternativa seria baixar o projeto no meu computador e fazer a confirmação inicial a partir daí, mas estou interessado em saber se existe uma opção no SVN para dividir a confirmação grande em mais, algo semelhante aos métodos de transações.

O desenvolvedor antes de mim nunca usou um sistema de controle de versão.


-1

A empresa em que trabalho força uma revisão de código por pares para cada confirmação. Portanto, qualquer confirmação que torne difícil para um colega descobrir o que está acontecendo e revisar em um período de tempo razoável é muito grande.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.