Gostaria de executar um conjunto de operações que exigem salvar e depois restaurar o HEAD.
Aqui está uma representação lógica do que eu gostaria de fazer:
# Save HEAD
original_head="$(cat .git/HEAD)"
# Perform other operations that muck with HEAD
# ...
# Restore HEAD
echo -n "$original_head" > .git/HEAD
O uso de cat
e echo
acima são meramente ilustrativos; eles não são nativos do git nem particularmente confiáveis, porque falharão em árvores de trabalho recém-criadas, onde .git
há um arquivo e não um diretório.
Uma abordagem um pouco melhor é usar symbolic-ref
:
# Save
original_head="$(git symbolic-ref HEAD)"
# Restore
git symbolic-ref HEAD "$original_head"
Essa abordagem é um pouco melhor, mas falha se HEAD foi originalmente destacado:
# Detach HEAD
git checkout $(git rev-parse HEAD)
# Try to get HEAD value to save:
git symbolic-ref HEAD
fatal: ref HEAD is not a symbolic ref
Aqui está o que estou fazendo atualmente para contornar isso:
# Save HEAD
symbolic_head=''
detached_head=''
if git symbolic-ref HEAD >/dev/null 2>&1; then
symbolic_head="$(git symbolic-ref HEAD)"
else
detached_head="$(git rev-parse HEAD)"
fi
# Perform other operations that muck with HEAD
# ...
# Restore HEAD
if [[ -n $symbolic_head ]]; then
git symbolic-ref HEAD "$symbolic_head"
else
git update-ref HEAD "$detached_head"
fi
Existe uma maneira mais direta de dizer "obter o valor de HEAD, independentemente de ser uma referência simbólica ou normal" e então "definir o valor de HEAD, independentemente de ser uma referência simbólica ou normal"?
Se você
enquanto você tiver uma ramificação verificada, sua restauração não fará nada, operações em um cabeçalho anexado afetam a ramificação, é assim que a anexação funciona.
O que você está pedindo é incomum o suficiente para que, se for realmente o que você quer, então acho que o que você está fazendo, apenas salvando o conteúdo de referência byte por byte e restaurando-o, seja a melhor e possivelmente a única maneira.
Mas há maneiras melhores de fazer tudo o que imaginei (pelo menos até agora) que você poderia querer com isso.
editar: ahhh, dos comentários, também alguns que não descobri:
HEAD
é uma convenção usada para a conveniência de comandos "porcelain", os comandos mais convencionais source-control-operatino. Se você não precisa do que eles fazem, use os comandos básicos subjacentes, o "plumbing":é a operação de baixo nível
git checkout
runs¹; o principal passo extra do checkout além disso é atualizarHEAD
para apontar para$thatrev
, se você soletrou como a forma abreviada de uma ref começandorefs/heads/
por anexarHEAD
a essa (ponta de ramificação) ref. Isso é realmente tudo o que há para fazer, o comando adquiriu muitas outras opções para fazer várias outras coisas convenientes ao longo do caminho, mas elas estão todas apenas encadeando comandos principais para atingir o efeito desejado.Se sua árvore de trabalho estiver suja, você provavelmente precisará
git read-tree --reset -m
de alguma outra limpeza antes que a árvore de leitura funcione. O Git não gosta de interferir em trabalhos não confirmados sem que você dê ordens explícitas.Para outros usos, uma árvore de trabalho de banda lateral com
git worktree add `mktemp -d`; cd $_
, remova a árvore de trabalho quando terminar e assim que terminar de adicionar a nova árvore de trabalho de ramificação para rastrear o que você estava fazendo, exclua-a também.Há muitas opções disponíveis nesse comando, se houver algum tipo de preparação que precise ser feita, veja a
--no-checkout
opção e talvez faça um hardlink para quaisquer arquivos necessários,git ls-files $options|cpio -pdl $thescratchtree
. E assim por diante.Eu, comecei com o Git antes do comando worktree existir e ainda faço qualquer sandbox de cirurgia de grande porte
git clone -ns . `mktemp -d`; cd $_
e faço do meu jeito com o clone, então qualquer resultado que eu queira eu empurro de volta. Isso ainda parece mais limpo e seguro para mim, especialmente para tentativas de cirurgia de grande porte.ps e a propósito:
se você estiver usando coisas de baixo nível,
original_head=$(cat .git/HEAD)
é mais desajeitadoread original_head <.git/HEAD
, e você pode simplesmenteecho $original_head >.git/HEAD
fazer a restauração.¹ o checkout realmente funciona
git read-tree -um HEAD $thatrev
, veja a documentação, isso acende muito mais verificações sobre o que está sendo alterado ou abandonado.