Zmień datę tagu git (lub opartą na nim wersję GitHub)

97

Dodaje wydania do moich projektów na GitHub, dodając tagi do różnych zatwierdzeń w gałęzi głównej.

W jednym z moich projektów nie dodałem tagów do zatwierdzeń w porządku chronologicznym. (Znalazłem oczywiste zatwierdzenia i oznaczyłem je, a następnie znalazłem mniej oczywiste, starsze zatwierdzenia i oznaczyłem je.)

Teraz GitHub pokazuje v1.0.1 jak prąd, z poprzedzającym go v0.7.0 i v1.1.2 poprzedzający że .

Wydaje się, że używa daty na utworzeniu tagu jako daty wydania zamiast zatwierdzania, które jest oznaczane. Jak mogę edytować moje tagi, aby ich daty były takie same jak zatwierdzenie, które tagują?

mapowanie wydań i dat między gitk i GitHub

Phrogz
źródło

Odpowiedzi:

120

OSTRZEŻENIE: to nie zachowa wiadomości z tagami dla tagów z adnotacjami.

Podsumowanie

Dla każdego tagu, który należy zmienić:

  1. Cofnij się w czasie do zatwierdzenia reprezentującego tag
  2. Usuń tag (lokalnie i zdalnie)
    • Spowoduje to zmianę „Wydania” na GitHub w wersję roboczą, którą możesz później usunąć.
  3. Ponownie dodaj tag o tej samej nazwie, używając magicznego wywołania, które ustawia jego datę na datę zatwierdzenia.
  4. Przenieś nowe tagi z ustalonymi datami z powrotem do GitHub.
  5. Przejdź do GitHub, usuń wszystkie wersje w wersji roboczej i ponownie utwórz nowe wersje z nowych tagów

W kodzie:

# Fixing tag named '1.0.1'
git checkout 1.0.1               # Go to the associated commit
git tag -d 1.0.1                 # Locally delete the tag
git push origin :refs/tags/1.0.1 # Push this deletion up to GitHub

# Create the tag, with a date derived from the current head
GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" git tag -a 1.0.1 -m"v1.0.1"

git push --tags                  # Send the fixed tags to GitHub

Detale

Zgodnie z How to Tag in Git :

Jeśli zapomnisz otagować wersję lub wersję, zawsze możesz oznaczyć je wstecz, w ten sposób:

git checkout SHA1_OF_PAST_COMMIT
git tag -m"Retroactively tagging version 1.5" v1.5

I chociaż jest to całkowicie użyteczne, powoduje to, że tagi są poza porządkiem chronologicznym, co może zaszkodzić systemom kompilacji, które szukają „najnowszego” tagu. Ale nie bój się. Linus pomyślał o wszystkim:

# This moves you to the point in history where the commit exists
git checkout SHA1_OF_PAST_COMMIT

# This command gives you the datetime of the commit you're standing on
git show --format=%aD  | head -1

# And this temporarily sets git tag's clock back to the date you copy/pasted in from above
GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800" git tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"

# Combining the two...
GIT_COMMITTER_DATE="$(git show --format=%aD  | head -1)" git tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"

Jeśli jednak dodałeś już tag, nie możesz użyć powyższego z, w git tag -f existingtagprzeciwnym razie git będzie narzekał podczas próby scalenia:

Rammy:docubot phrogz$ git push --tags
To [email protected]:Phrogz/docubot.git
 ! [rejected]        1.0.1 -> 1.0.1 (already exists)
error: failed to push some refs to '[email protected]:Phrogz/docubot.git'
hint: Updates were rejected because the tag already exists in the remote.

Zamiast tego musisz usunąć tag lokalnie:

git tag -d 1.0.1

Zdalnie wypchnij to usunięcie :

git push origin :refs/tags/1.0.1

W serwisie GitHub załaduj ponownie wersje - wydanie zostało oznaczone jako „wersja robocza” - i usuń wersję roboczą.

Teraz dodaj tag z datą wsteczną zgodnie z powyższymi instrukcjami, a na koniec prześlij wynikowy tag do GitHub:

git push --tags

a następnie przejdź i ponownie dodaj informacje o wersji GitHub.

Phrogz
źródło
2
Oto skrypt bash, który usuwa i ponownie dodaje każdy tag w repozytorium git:git tag -l | while read -r tag; do `git checkout $tag && git tag -d $tag && git push origin :refs/tags/$tag && GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" git tag -a $tag -m"$tag"`; done; git push --tags
Phrogz,
2
używanie git tag -afczyni -dniepotrzebnymi i pozostajesz lokalnie, więc możesz sprawdzić, czy wszystko jest w porządku - wtedy możeszgit push --tags -f
Mr_and_Mrs_D
Dzięki @vmrob, to zadziałało (chociaż musiałem kilkakrotnie wprowadzić moje hasło GitHub).
Colonel Panic
3
@Mr_and_Mrs_D Dobra sugestia i dobry sposób na ograniczenie tej operacji do jednego naciśnięcia. Mając to na uwadze, myślę, że wynikowy (niesprawdzony) git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH ; done && git push --tags --force
jednolinijkowy
2
Działa to w powłoce git dla PowerShell, ale musisz ustawić zmienną środowiskową inaczej i zrobić to w dwóch wierszach: $env:GIT_COMMITTER_DATE="Thu Nov 11 12:21:57 2010 -0800"igit tag -a 0.9.33 -m"Retroactively tagging version 0.9.33"
roncli
18

Oto jedna linijka oparta na niektórych komentarzach w drugiej odpowiedzi:

git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH ; done && git push --tags --force

OSTRZEŻENIE: spowoduje to zniszczenie twoich zewnętrznych tagów i nie zachowa wiadomości dla tagów z adnotacjami! Upewnij się, że wiesz, co robisz i ZDECYDOWANIE nie rób tego dla publicznego repozytorium !!!

Aby to rozbić ...

# Loop over tags
git tag -l | while read -r tag
do

    # get the commit hash of the current tag
    COMMIT_HASH=$(git rev-list -1 $tag)

    # get the commit date of the tag and create a new tag using
    # the tag's name and message. By specifying the environment
    # environment variable GIT_COMMITTER_DATE before this is
    # run, we override the default tag date. Note that if you
    # specify the variable on a different line, it will apply to
    # the current environment. This isn't desired as probably
    # don't want your future tags to also have that past date.
    # Of course, when you close your shell, the variable will no
    # longer persist.
    GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$tag" $COMMIT_HASH


done

# Force push tags and overwrite ones on the server with the same name
git push --tags --force

Podziękowania dla @Mr_and_Mrs_D za sugestię użycia pojedynczego naciśnięcia.

vmrob
źródło
3

Opierając się na innych odpowiedziach, oto sposób, który pozwoli zachować pierwszą linię wiadomości z tagiem

git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" git tag -a -f $tag -m"$COMMIT_MSG" $COMMIT_HASH ; done
git tag -l -n1           #check by listing all tags with first line of message
git push --tags --force  #push edited tags up to remote

Bit odpowiedzialny za zachowanie wiadomości to:

COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1)

head -n1weźmie pierwszą linię starego komunikatu o zatwierdzeniu. Możesz go zmienić na -n2lub-n3 etc, aby zamiast tego uzyskać dwie lub trzy linie.

Jeśli chcesz zmienić datę / godzinę tylko dla jednego tagu, możesz rozbić jeden wiersz, aby zrobić to w powłoce bash:

tag=v0.1.0
COMMIT_HASH=$(git rev-list -1 $tag)
COMMIT_MSG=$(git tag -l --format='%(contents)' $tag | head -n1)
COMMIT_DATE=$(git show $COMMIT_HASH --format=%aD | head -1)
GIT_COMMITTER_DATE=$COMMIT_DATE git tag -s -a -f $tag -m"$COMMIT_MSG" $COMMIT_HASH

Bibliografia:

weiji14
źródło
To świetnie, dzięki. Jednak w poleceniach do zmiany pojedynczego tagu jest -sflaga, której nie ma w jednowierszowym , więc otrzymywałem, error: gpg failed to sign the dataponieważ nie mam skonfigurowanego podpisu dla git. Ten błąd trochę mnie wytrącił.
wch