Sou novo no controle de versão e entendo que "confirmar" é essencialmente criar um backup enquanto atualiza a nova versão 'atual' do que você está trabalhando.
O que eu não entendo é para que serve a encenação de uma perspectiva prática. Encenar é algo que existe apenas no nome ou tem um propósito? Quando você se compromete, vai comprometer tudo de qualquer maneira, certo?
Edit: Eu acho que posso estar confundindo a terminologia. Um arquivo 'testado' é a mesma coisa que um arquivo 'rastreado'?
Respostas:
Quando você confirma, ele apenas confirma as mudanças no índice (os arquivos "testados"). Há muitos usos para isso, mas o mais óbvio é dividir suas mudanças de trabalho em partes menores e independentes. Talvez você tenha corrigido um bug enquanto implementava um recurso. Você pode
git add
apenas esse arquivo (ougit add -p
adicionar apenas parte de um arquivo!) E, em seguida, confirmar a correção do bug antes de confirmar todo o resto. Se você estiver usando,git commit -a
então você está apenas forçando umadd
de tudo antes do commit. Não use-a
se quiser tirar proveito dos arquivos de teste.Você também pode tratar os arquivos testados como uma cópia de trabalho intermediária com
--cached
muitos comandos. Por exemplo,git diff --cached
mostrará como o estágio difereHEAD
para que você possa ver o que está prestes a comprometer sem misturar suas outras alterações de trabalho.fonte
git reset --hard
.git diff --staged
e verificar quais arquivos você alterou e onde e começar a fazer outras alterações.fonte
Um propósito prático da preparação é a separação lógica de confirmações de arquivo.
Como o teste permite que você continue fazendo edições nos arquivos / diretório de trabalho e faça commits em partes quando achar que tudo está pronto, você pode usar estágios separados para edições logicamente não relacionadas.
Suponha que você tem 4 arquivos
fileA.html
,fileB.html
,fileC.html
efileD.html
. Você faz alterações em todos os 4 arquivos e está pronto para confirmar, mas as alterações emfileA.html
efileB.html
estão logicamente relacionadas (por exemplo, a mesma implementação de novo recurso em ambos os arquivos), enquanto as alterações emfileC.html
efileD.html
são separadas e logicamente não relacionadas aos arquivos anteriores. Pode primeiros arquivos de estágiofileA.html
efileB.html
e comprometer aqueles.Então, na próxima etapa, você prepara e confirma as alterações nos dois arquivos restantes.
fonte
git commit -m "Implemented new feature XYZ" fileA.html fileB.html
funcionaria bem sem a necessidade dos comandos git add. Eu venho de um mundo de subversão, onde o staging não é um conceito, então, não estou convencido sobre a utilidade do git stagingÉ mais fácil entender o uso dos comandos git
add
ecommit
se você imaginar um arquivo de log sendo mantido em seu repositório no Github. O arquivo de registro de um projeto típico para mim pode ser assim:Normalmente começo meu dia com um
git pull
pedido e termino com umgit push
pedido. Portanto, tudo dentro do registro de um dia corresponde ao que ocorre entre eles. Durante cada dia, há uma ou mais tarefas lógicas que eu concluo que exigem a alteração de alguns arquivos. Os arquivos editados durante essa tarefa são listados em um índice.Cada uma dessas subtarefas (Tarefa A e Tarefa B aqui) são confirmações individuais. O
git add
comando adiciona arquivos à lista 'Índice de arquivos alterados'. Esse processo também é chamado de teste. Ogit commit
comando registra / finaliza as alterações e a lista de índice correspondente junto com uma mensagem personalizada.Lembre-se de que você ainda está alterando apenas a cópia local do seu repositório e não a do Github. Depois disso, somente quando você fizer um 'git push', faça todas essas mudanças registradas, junto com seus arquivos de índice para cada commit, logado no repositório principal (no Github).
Por exemplo, para obter a segunda entrada nesse arquivo de log imaginário, eu teria feito:
Resumindo,
git add
egit commit
permite que você divida uma alteração no repositório principal em sub-alterações lógicas sistemáticas. Como outras respostas e comentários apontaram, é claro que há muitos outros usos para eles. No entanto, este é um dos usos mais comuns e um princípio orientador por trás do Git ser um sistema de controle de revisão de vários estágios, ao contrário de outros populares como o Svn.fonte
A área de teste nos ajuda a criar os commits com maior flexibilidade. Por crafting, quero dizer dividir os commits em unidades lógicas. Isso é muito importante se você deseja um software sustentável. A maneira mais óbvia de conseguir isso:
Você pode trabalhar em vários recursos / bugs em um único diretório de trabalho e ainda criar commits significativos. Ter um único diretório de trabalho que contém todo o nosso trabalho ativo também é muito conveniente. (Isso pode ser feito sem uma área de teste, apenas contanto que as alterações nunca se sobreponham a um arquivo. E você também tem a responsabilidade adicional de rastrear manualmente se elas se sobrepõem)
Você pode encontrar mais exemplos aqui: Usos do índice
E o melhor é que as vantagens não param nesta lista de workflows. Se um fluxo de trabalho exclusivo surgir, você pode ter quase certeza de que a área de preparação o ajudará.
fonte
Para expandir a resposta de Ben Jackson , o que é bom, vamos examinar a pergunta original de perto. (Veja sua resposta para perguntas do tipo por que incomodar ; isso é mais sobre o que está acontecendo .)
Isso não está certo. Backups e controle de versão estão certamente relacionados - exatamente quão fortemente depende de algumas coisas que são, até certo ponto, questões de opinião - mas certamente existem algumas diferenças, mesmo que apenas na intenção: Backups são normalmente projetados para recuperação de desastres (falha de máquina, destruição de fogo edifício inteiro, incluindo todos os meios de armazenamento, etc.). O controle de versão é normalmente projetado para interações mais refinadas e oferece recursos que os backups não oferecem. Normalmente, os backups são armazenados por algum tempo e, em seguida, descartados como "muito antigos": um backup mais recente é tudo o que importa. O controle de versão normalmente salva cada versão confirmada para sempre.
Sim e não. O design do Git aqui é um tanto peculiar. Existem sistemas de controle de versão que não requerem uma etapa de teste separada. Por exemplo, o Mercurial, que é muito parecido com o Git em termos de uso, não requer uma
hg add
etapa separada , além da primeira que apresenta um arquivo totalmente novo. Com o Mercurial, você usa ohg
comando que seleciona alguns commit, então você faz seu trabalho, então você executahg commit
e pronto. Com o Git, você usagit checkout
, 1 então você faz seu trabalho, então você executagit add
, e entãogit commit
. Por que agit add
etapa extra ?O segredo aqui é o que o Git chama, de forma variada, de índice ou área de teste ou, às vezes - raramente hoje em dia - de cache . Todos esses são nomes para a mesma coisa.
Não, mas eles estão relacionados. Um arquivo rastreado é aquele que existe no índice do Git. Para entender o índice corretamente, é bom começar entendendo os commits.
Desde Git versão 2.23, você pode usar em
git switch
vez degit checkout
. Para este caso específico, esses dois comandos fazem exatamente a mesma coisa. O novo comando existe porquegit checkout
ficou sobrecarregado com muitas coisas; eles foram divididos em dois comandos separadosgit switch
egit restore
, para tornar mais fácil e seguro o uso do Git.Compromissos
No Git, um commit salva um instantâneo completo de todos os arquivos que o Git conhece. (Quais arquivos o Git conhece? Veremos isso na próxima seção.) Esses instantâneos são armazenados em um formato especial, somente leitura, somente Git, compactado e desduplicado, que em geral apenas o próprio Git pode ler . (Há mais coisas em cada commit do que apenas este instantâneo, mas isso é tudo que cobriremos aqui.)
A eliminação da duplicação ajuda com espaço: normalmente mudamos apenas alguns arquivos e, em seguida, fazemos um novo commit. Portanto, a maioria dos arquivos em um commit são basicamente os mesmos que os arquivos no commit anterior. Simplesmente reutilizando esses arquivos diretamente, o Git economiza muito espaço: se tocarmos em apenas um arquivo, o novo commit ocupará apenas espaço para uma nova cópia. Mesmo assim, ele é compactado - às vezes muito compactado, embora isso realmente aconteça mais tarde - de forma que um
.git
diretório pode realmente ser menor do que os arquivos que contém, uma vez que são expandidos para arquivos normais do dia a dia. A eliminação da duplicação é segura porque os arquivos confirmados ficam congelados para sempre. Ninguém pode mudar um, então é seguro que os commits dependam das cópias uns dos outros.Como os arquivos armazenados estão neste formato especial, congelado para sempre, somente Git, o Git precisa expandir cada arquivo em uma cópia comum do dia a dia. Esta cópia comum não é a cópia do Git : é a sua cópia, para fazer o que quiser. O Git apenas escreverá para eles quando você disser para fazer isso, para que você tenha suas cópias para trabalhar. Essas cópias utilizáveis estão em sua árvore de trabalho ou árvore de trabalho .
O que isso significa é que quando você verifica algum commit em particular, há automaticamente duas cópias de cada arquivo:
Git tem uma cópia congelada para sempre, Git-ified no commit atual . Você não pode mudar esta cópia (embora você possa, é claro, selecionar um commit diferente, ou fazer um novo commit).
Você tem, em sua árvore de trabalho, uma cópia em formato normal. Você pode fazer o que quiser, usando qualquer um dos comandos do seu computador.
Outros sistemas de controle de versão (incluindo Mercurial como mencionado acima) param aqui, com essas duas cópias. Você apenas modifica sua cópia da árvore de trabalho e depois efetua o commit. Git ... não.
O índice
Entre essas duas cópias, o Git armazena uma terceira cópia 2 de cada arquivo. Esta terceira cópia está no formato congelado , mas ao contrário da cópia congelada no commit, você pode alterá-la. Para mudar, você usa
git add
.O
git add
comando significa fazer com que a cópia do índice do arquivo corresponda à cópia da árvore de trabalho . Isto é, você está dizendo ao Git: Substitua a cópia congelada e não duplicada que está no índice agora, compactando minha cópia da árvore de trabalho atualizada, deduplicando-a e preparando-a para ser congelada em um novo commit. Se você não usargit add
, o índice ainda mantém a cópia em formato congelado do commit atual.Quando você executa
git commit
, Git pacotes até tudo o que está no índice direito, em seguida, para o uso como o novo snapshot. Como já está no formato congelado e pré-desduplicado, o Git não precisa fazer muito trabalho extra.Isso também explica o que são os arquivos não rastreados . Um arquivo não rastreado é um arquivo que está em sua árvore de trabalho, mas não está no índice do Git agora . Não importa como o arquivo terminou neste estado. Talvez você tenha copiado de algum outro lugar em seu computador, em sua árvore de trabalho. Talvez você o tenha criado fresco aqui. Talvez haja era uma cópia no índice do Git, mas você removeu essa cópia com
git rm --cached
. De uma forma ou de outra, existe uma cópia aqui na sua árvore de trabalho, mas não existe uma cópia no índice do Git. Se você fizer um novo commit agora, esse arquivo não estará no novo commit.Note que
git checkout
inicialmente preenche o índice do Git a partir do commit que você verificou. Portanto, o índice começa correspondendo ao commit. Git também preenche sua árvore de trabalho a partir desta mesma fonte. Então, inicialmente, todos os três combinam. Quando você altera arquivos em sua árvore de trabalho egit add
eles, bem, agora o índice e sua árvore de trabalho combinam. Então você executagit commit
e o Git faz um novo commit do índice, e agora todos os três se casam novamente.Como o Git faz novos commits do índice, podemos colocar as coisas desta forma: o índice do Git contém o próximo commit que você planeja fazer. Isso ignora a função expandida que o índice do Git assume durante uma mesclagem em conflito, mas gostaríamos de ignorar isso por enquanto. :-)
É só isso - mas ainda é muito complicado! É particularmente complicado porque não há uma maneira fácil de ver exatamente o que está no índice do Git. 3 Mas não é um comando Git que lhe diz o que está acontecendo, de uma maneira que é muito útil, e que comando é
git status
.2 Tecnicamente, isso não é realmente uma cópia . Em vez disso, é uma referência ao arquivo Git-ified, pré-deduplicado e tudo. Há mais coisas aqui também, como o modo, nome do arquivo, um número de teste e alguns dados de cache para tornar o Git mais rápido. Mas, a menos que você comece a trabalhar com alguns dos comandos de baixo nível do Git -
git ls-files --stage
egit update-index
em particular - você pode apenas pensar nisso como uma cópia.3 O
git ls-files --stage
comando mostrará os nomes e números de teste de cada arquivo no índice do Git, mas geralmente isso não é muito útil de qualquer maneira.git status
O
git status
comando realmente funciona executando doisgit diff
comandos separados para você (e também fazendo algumas outras coisas úteis, como informar em qual branch você está).O primeiro
git diff
compara o commit atual - que, lembre-se, está congelado para sempre - com o que quer que esteja no índice do Git. Para arquivos iguais , o Git não dirá nada. Para arquivos que são diferentes , Git irá dizer-lhe que este arquivo é encenado para cometer . Isso inclui todos os novos arquivos-se a cometer não temsub.py
nele, mas o índice não têmsub.py
nele, então é acrescentado e esse arquivo quaisquer arquivos removidos, que eram (e são) no cometer, mas não estão em o índice mais (git rm
, talvez).O segundo
git diff
compara todos os arquivos no índice do Git com os arquivos em sua árvore de trabalho. Para arquivos que são iguais , o Git não diz nada. Para arquivos que são diferentes , o Git dirá que esse arquivo não foi testado para confirmação . Ao contrário do primeiro diff, esta lista particular não inclui arquivos que são todos novos: se o arquivountracked
existe em sua árvore de trabalho, mas não no índice do Git, Git apenas o adiciona à lista de arquivos não rastreados . 4No final, tendo acumulado esses arquivos não rastreados em uma lista,
git status
irá anunciar os nomes desses arquivos também, mas há uma exceção especial: se o nome de um arquivo estiver listado em um.gitignore
arquivo, isso suprime esta última listagem. Observe que listar um arquivo rastreado - aquele que está no índice do Git - em um.gitignore
não tem efeito aqui : o arquivo está no índice, então ele é comparado e confirmado, mesmo se estiver listado em.gitignore
. O arquivo para ignorar apenas suprime as reclamações de "arquivo não rastreado". 54 Ao usar a versão curta de
git status
-git status -s
—os arquivos não rastreados não são separados, mas o princípio é o mesmo. Acumular os arquivos dessa forma também permitegit status
resumir vários nomes de arquivos não rastreados, apenas imprimindo um nome de diretório, às vezes. Para obter a lista completa, usegit status -uall
ougit status -u
.5 Listar um arquivo também faz com que em massa adicione muitas operações de arquivo , como
git add .
ougit add *
pule o arquivo não rastreado. Esta parte fica um pouco mais complicada, pois você pode usargit add --force
para adicionar um arquivo que normalmente seria ignorado. Existem alguns outros casos especiais normalmente menores, todos os quais se somam a isso: o arquivo.gitignore
pode ser chamado mais apropriadamente.git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-them
ou algo igualmente difícil de manejar. Mas isso é muito ridículo,.gitignore
é.git add -u
,git commit -a
etcExistem vários atalhos úteis que você deve conhecer aqui:
git add .
irá adicionar todos os arquivos atualizados no diretório atual e qualquer subdiretório. Isso respeita.gitignore
, portanto, se um arquivo que não está sendo rastreadogit status
não receber uma reclamação de , ele não será adicionado automaticamente.git add -u
irá adicionar automaticamente todos os arquivos atualizados em qualquer lugar em sua árvore de trabalho . 6 Isso afeta apenas os arquivos rastreados . Observe que se você removeu a cópia da árvore de trabalho, isso removerá a cópia do índice também (git add
faz isso como parte de fazer com que o índice corresponda à árvore de trabalho ).git add -A
é como corrergit add .
do nível superior de sua árvore de trabalho (mas veja a nota de rodapé 6).Além disso, você pode correr
git commit -a
, o que equivale a aproximadamente 7 a corrergit add -u
e entãogit commit
. Ou seja, você obtém o mesmo comportamento conveniente no Mercurial.Em geral, desaconselho o
git commit -a
padrão: acho que é melhor usar comgit status
frequência, observe atentamente a saída e, se o status não for o que você esperava, descubra por que é esse o caso. Usandogit commit -a
, é muito fácil modificar acidentalmente um arquivo e enviar uma alteração que você não pretendia. Mas isso é principalmente uma questão de gosto / opinião.6 Se a sua versão do Git for anterior ao Git 2.0, tome cuidado aqui:
git add -u
só funciona no diretório e subdiretórios atuais, então você deve subir ao nível superior da sua árvore de trabalho primeiro. Agit add -A
opção tem um problema semelhante.7 Digo aproximadamente equivalente porque
git commit -a
na verdade funciona criando um índice extra e usando esse outro índice para fazer o commit. Se o commit funcionar , você terá o mesmo efeito que fazergit add -u && git commit
. Se o commit não funcionar - se você fizer o Git pular o commit de qualquer uma das muitas maneiras que você pode fazer isso - então nenhum arquivo serágit add
executado depois, porque o Git joga fora o índice extra temporário e volta a usar o índice principal .Existem complicações adicionais que surgem se você usar
git commit --only
aqui. Nesse caso, o Git cria um terceiro índice, e as coisas ficam muito complicadas, especialmente se você usar ganchos de pré-confirmação. Este é outro motivo para usargit add
operações separadas .fonte
Eu vejo o ponto de usar o stage para fazer commits menores, conforme mencionado por @Ben Jackson e @Tapashee Tabassum Urmi e às vezes eu o uso para esse propósito, mas eu principalmente o uso para tornar meus commits maiores! aqui está o meu ponto:
Digamos que eu queira adicionar um pequeno recurso que requer várias etapas menores. Não vejo sentido em ter um commit separado para etapas menores e inundar minha linha do tempo. No entanto, quero salvar cada etapa e voltar, se necessário,
Simplesmente enceno os passos menores um em cima do outro e quando sinto que vale a pena me comprometer, eu me comprometo. Desta forma, eu removo os commits desnecessários da linha do tempo, mas capaz de desfazer (checkout) a última etapa.
Vejo outras maneiras de fazer isso (simplificando o histórico do git) que você pode usar de acordo com sua preferência:
fonte
É como uma caixa de seleção que permite escolher quais arquivos enviar.
por exemplo, se eu editei
fileA.txt
efileB.txt
.Mas quero confirmar as alterações defileA.txt
apenas. porque ainda não termineifileB.txt
.Posso simplesmente usar
git add fileA.txt
e comprometer usandogit commit -m "changed fileA.txt"
e continuar trabalhando comfileB.txt
e depois de terminar posso comprometerfileB.txt
facilmentefonte