Adicione um submódulo git usando Rugged

Esta dica demonstra como construir um commit usando Rugged que irá adicionar um submódulo a um repositório git.

Rugged é uma biblioteca que fornece ligações de API Ruby para libgit2 , uma implementação C das operações git. O Rugged está substituindo rapidamente o grão e bibliotecas Ruby semelhantes porque executa operações no repositório git usando chamadas de API diretas em vez de chamar git como um comando do sistema.

A partir da versão 0.19.0, o Rugged não fornece uma API para adicionar um submódulo a um repositório git. No entanto, ele fornece os recursos de baixo nível necessários para construir uma referência de submódulo manualmente. Você só precisa entender como um submódulo é rastreado no repositório git.

Começaremos criando um repositório sem usar o Rugged para estabelecer um ponto de partida.

git_email = 'octocat@github.com'
git_name
= 'The Octocat'
repo_name
= 'sample-repo'

Dir.mkdir repo_name
Dir.chdir repo_name do
File.open 'README.adoc', 'w' do |f|
f
.write %(= READMEnnYou will read me and be informed.)
end
`git init .`
`git add README.adoc`
`git commit -m "add README" --author "#{git_name} <#{git_email}>" README.adoc`
end

Você pode inspecionar o repositório para ver se ele tem um arquivo e um commit.

Agora usaremos o Rugged para adicionar um arquivo .gitmodules e outro arquivo especial que indica qual commit usar do repositório do submódulo.

require 'rugged'

submodule_path
= 'example-submodule'
submodule_url
= 'https://github.com/octocat/Spoon-Knife.git'
submodule_last_commit
= 'd0dd1f61b33d64e29d8bc1372a94ef6a2fee76a9'

# (1)
repo
= Rugged::Repository.new repo_name

# (2)
repo
.checkout 'refs/heads/master'

# (3)
index
= repo.index

# (4)
File.open File.join(repo.workdir, '.gitmodules'), 'w' do |f|
f
.write %([submodule "#{submodule_path}"]
tpath
= #{submodule_path}
turl
= #{submodule_url})
end
index
.add path: '.gitmodules',
oid
: (Rugged::Blob.from_workdir repo, '.gitmodules'),
mode
: 0100644

# (5)
index
.add path: submodule_path,
oid
: submodule_last_commit,
mode
: 0160000

# (6)
commit_tree
= index.write_tree repo

# (7)
index
.write

# (8)
commit_author
= { email: git_email, name: git_name, time: Time.now }
Rugged::Commit.create repo,
author
: commit_author,
committer
: commit_author,
message
: 'Adding example submodule',
parents
: [repo.head.target],
tree
: commit_tree,
update_ref
: 'HEAD'

Aqui está o que este código está fazendo:

  • (1) Carregue o repositório no Rugged
  • (2) Certifique-se de que estamos no ramo certo (por exemplo, refs / heads / master)
  • (3) Recupere uma referência ao índice do repositório para este ramo
  • (4) Construir o arquivo .gitmodules, gravá-lo no disco e adicioná-lo ao índice do repositório
  • (5) Adicione o arquivo de referência especial que estabelece o commit do subprojeto (ou seja, que se compromete a usar do repositório do submódulo)
  • (6) Grave as alterações feitas no índice no repositório git (ou seja, o banco de dados git)
  • (7) Sincronizar o índice e o diretório de trabalho (não modifica o diretório de trabalho)
  • (8) Crie um novo commit e atualize o HEAD para apontar para ele

A etapa mais importante neste processo é a # 5, que cria o arquivo que estabelece o commit do subprojeto.

Quando você olha para o diff do último commit, você verá a seguinte entrada:

diff --git a/example-submodule b/example-submodule
new file mode 160000
index
0000000..d0dd1f6
--- /dev/null
+++ b/example-submodule
@@ -0,0 +1 @@
+Subproject commit d0dd1f61b33d64e29d8bc1372a94ef6a2fee76a9

Você notará que o modo usado é 0160000. Este é um modo especial que diz ao git que este não é um arquivo regular, mas sim uma referência de commit de subprojeto (isto é, submódulo). Embora pareça que git criou um arquivo contendo uma linha que começa com “Subproject commit”, não há nenhum arquivo com esse conteúdo no disco. Esse conteúdo é gerado automaticamente e faz parte do objeto interno que armazena as informações do submódulo.

Esta é a aparência do arquivo .gitmodule quando terminarmos.

[submodule "example-submodule"]
path
= example-submodule
url
= https://github.com/octocat/Spoon-Knife.git

Agora clone este repositório com habilitação de recursão em uma pasta adjacente.

$ git clone --recursive sample-repo sample-repo-clone

Você deve ver que a operação de clone recupera com sucesso o repositório do submódulo.