push do remote repo i magiczny error

0

Hej, mam dziwny problem z git, jak zawsze zaskakuje mnie swoją magią ^^

Proces tworzenia repozytorium w moim przypadku wygląda następująco:

  1. Sprawdzam wszystkie lokalne branche (aktualnie jestem na master)
$ git branch -vv           
* master         aeaa98a [origin/master] add readme
  1. Sprawdzam czy są jakieś nowości
$ git pull --rebase
Current branch master is up to date.
  1. Jesli nie to tworzę nowego brancha
$ git checkout -b Jacek/gameMenu
Switched to a new branch 'Jacek/gameMenu'
  1. Od razu tworzę remote branch
$ git push origin Jacek/gameMenu
Total 0 (delta 0), reused 0 (delta 0)
To <nazwa_repozytorium>.git
 * [new branch]      Jacek/gameMenu -> Jacek/gameMenu
  1. Mam utworzony lokalny branch i remote więc mogę już działać i coś tam tworzyć

  2. Po części wykonanej pracy chcę wypchać moje zmiany na remote

$ git status              // zmiany sa
$ git add .               // stage 
$ git commit -m "first version of game menu"
[Jacek/gameMenu 42a81c6] first version of game menu
 20 files changed, 400 insertions(+), 14 deletions(-)
$ git status
On branch Jacek/gameMenu
nothing to commit, working tree clean
  1. Do tego momentu jest ok, więc push
$ git push origin Jacek/gameMenu
Counting objects: 22, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (21/21), done.
Writing objects: 100% (22/22), 25.88 MiB | 72.00 KiB/s, done.
Total 22 (delta 3), reused 0 (delta 0)
To <nazwa_repozytorium>.git
   aeaa98a..42a81c6  Jacek/gameMenu -> Jacek/gameMenu
  1. Push z pierwszymi zmianami poszedł

  2. Znów chcę wysłać zmiany na remote, ale nie chce tworzyć nowego commita tylko pracować cały czas na tym samym (patch set nr x)

$ git status        // mamy nowe zmiany
$ git add .         // leci do stage
$ git commit --amend
[Jacek/gameMenu e524f8d] first version of game menu
 Date: Wed Nov 23 18:42:07 2016 +0100
 22 files changed, 444 insertions(+), 14 deletions(-)

coś tam potworzył...

  1. Gotowi na push ?
$ git status
On branch Jacek/gameMenu
nothing to commit, working tree clean
  1. Jednak się nie da ???!!
$ git push origin Jacek/gameMenu
To <nazwa_repozytorium>.git
 ! [rejected]        Jacek/gameMenu -> Jacek/gameMenu (non-fast-forward)
error: failed to push some refs to '<nazwa_repozytorium>.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

I tu pojawia się problem, którego próbuje usilnie pokonać ale mi się nie udaje :(
próbowałem również pushować tak:
$ git push origin HEAD:refs/for/Jacek/gameMenu
ale jest ten sam błąd.

Próbowałem skorzystać z hinta i zrobić pull:

$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> Jacek/gameMenu

lub:

$ git pull origin/Jacek/gameMenu Jacek/gameMenu
fatal: 'origin/Jacek/gameMenu' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

ale nie podziałało.

W codziennej pracy tak samo działam jak powyżej z tą różnicą, że jak pushuje to:
$ git push origin HEAD:refs/for/jakisBranch

ale na tym repo, z którym się łącze z domu gdzie to repo jest na serwerze uczelni mam taki dziwny problem.

Byłbym wdzięczny za pomoc w tym magicznym przypadku

6

Rozrysujmy sobie co się stało:

a - początkowy commit (branch, remote/branch)

Następnie zrobiłeś jakieś zmiany, i zakommitowałeś je. Więc twoje repo wygląda tak:

a - początkowy commit
|
b - nowy commit (branch, remote/branch)

Następnie wprowadziłeś jakieś zmiany, i wykonałeś git commit --amend (to jest bardzo ważne). W związku z tym, że commity w gicie są niemutowalne (nie da się zmienić ich treści) de facto utworzyłeś nową gałąź i teraz repo wygląda tak:

a - początkowy commit
|\
b \ - nowy commit (remote/branch)
  |
  b' - nowy (zmieniony) commit (branch)

I tutaj mamy problem. Nie możesz wypchnąć commita b' bo nie jest to potomek b tylko jego rodzeństwo.

Rozwiązania masz 2:

  • zrobić git merge remote/branch i uzyskać repo w postaci:
a - początkowy commit
|\
b'\ - nowy (zmieniony) commit
| |
| b - nowy commit (remote/branch)
|/
c - merge remote/branch into branch (branch)

dzięki czemu c jest teraz potomkiem remote/branch i git push przejdzie

  • zrobić git push -f i nadpisać publiczną historię

Ogólną zasadą jest, że nie nadpisuje się publicznej historii. Są od tej zasady wyjątki przy rozproszonych repozytoriach, ale to nie jest temat na teraz. Zasadą dla Ciebie powinno być, że komenda git commit --amend jest absolutnym no-go po tym jak zrobisz git push.

0

wow fajne wyjaśnienie, polecasz jakiś tutorial/ książkę do gita żeby go dobrze zrozumieć?

co do amend, w pracy używamy gerrita, i flow jest takie: commit, push do gerrita, i jak chcesz dać patcha to wtedy commit amend i ładnie działa mimo, że po pushu. why?

2
  1. Znów chcę wysłać zmiany na remote, ale nie chce tworzyć nowego commita tylko pracować cały czas na tym samym (patch set nr x)

WTF.

0

No co, jak zrobisz commita, pusha, ale nie przejdzie code review to musisz commita poprawić (patch), nie?

0

@Krwawy Pomidor jak commit nie przejdzie to robisz nowy, który poprawia istniejący. Na Gerricie AFAIK nie robisz review poszczególnych commitów (bo to rzadko kiedy ma sens) jak już to się robi review całego brancha. A jak już musisz nadpisywać swoje zmiany to zrób to w osobnym repo lub lokalnie, a wypychaj po zakończeniu pracy.

0

code review każdego commita jest, o to chodzi żeby do głównego repo nic złego nie weszło, jak jest źle cokolwiek to leci -2 od architekta albo się wywali to -1 od jenkinsa i musisz dać --amend i znów push żeby poprawić. Byle change Id to samo było (wtedy działa to jak "patch") bo inaczej merge conflict z samym sobą gwarantowany:D no ale to specyficzny przypadek używania pośrednika jakim jest gerrit, dopiero submit (a nie push) tak naprawdę merguje commita do głównego repo, stąd po pushu można normalnie --amenda dać. To tak tylko w ramach sprostowania i ciekawostki:)

3

Od tego jest Git i w ogóle idea rozproszonej kontroli wersji, żeby nie trzeba było tak cudować.
Powinno się pracować na osobnej branczy, na której możesz sobie robić commity, amendy, jak chcesz.
Brancza powinna przejść review w całości, i dopiero robisz push.
Do mastera nic „złego” nie wejdzie, bo przy pushu wejdzie od razu z poprawką.

Robicie pod górkę i wbrew filozofii Gita.

To nie SVN że nad każdym commitem trzeba się pieścić i zastanawiać czy już a może jeszcze nie.

4
Biały Orzeł napisał(a):

code review każdego commita jest, o to chodzi żeby do głównego repo nic złego nie weszło, jak jest źle cokolwiek to leci -2 od architekta albo się wywali to -1 od jenkinsa i musisz dać --amend i znów push żeby poprawić. Byle change Id to samo było (wtedy działa to jak "patch") bo inaczej merge conflict z samym sobą gwarantowany:D no ale to specyficzny przypadek używania pośrednika jakim jest gerrit, dopiero submit (a nie push) tak naprawdę merguje commita do głównego repo, stąd po pushu można normalnie --amenda dać. To tak tylko w ramach sprostowania i ciekawostki:)

Git powstał po to, aby ułatwić programistom życie, nie utrudnić. To, co Wy robicie, to próba wyregulowania cylindrów w silniku przez rurę wydechową, jakieś szczytowe osiągnięcie programistycznej ginekologii.

Wyślijcie tego waszego arcytekta na szkolenie z Gita, najlepiej gdzieś na północną Syberię. Tylko nie zapomnijcie go wcześniej przebrać za samicę niedźwiedzia polarnego.

0

ahahah dzięki panowie:D no spoko, też mi się tak wydawało, że dziwnie używać gita gdzie nie robimy w ogóle branchy, tj można robić drafty na których pracuje po x osób przed submitem (po pushu) ale to jest tak rozebane że już lepiej nie.
A znacie jakies narzędzia ułatwiające code review branchy tak, żeby pracować z gitem zgodnie z założeniami, ale jednak code review oficjalnie przed mergem tego brancha do mastera musiał być?
I 2gie pytanie jak juz w temacie jesteśmy, powiedzmy, że 5 osób pracuje nad 1 dużą funkcjonalnością (120md), ale zmiany są kilku aplikacjach (integrowanych) / wieelu modułach itp itd, i sprinty są np 2 tygodniowe, jak wtedy te branche ogarnąć? tj 1 branch to praca 1 osoby przez 1 sprint czy jak? Jak często się to to merguje? 5 osób jednak co innego robi ale często w tych samych plikach lub w plikach na których pracują inne zespoły, jak ogarnąć tak duże merge conflicty?

0

Odpowiedzią na pierwsze pytanie jest GitLab (lub GitHub jeśli was stać) oraz odpowiednio udtawione hooki i narzędzia (przykładowo https://lgtm.co/).
Odpowiedzią na drugie pytanie jest:

  • Branche na origin
  • master - to jest wersja, która leży na stagingu (najczęściej zablokowana przed bezpośrednimi pushami, w GL masz taką opcję)
  • Tag z wersją dla każdego release na produkcji (polecam użyć SemVer)
  • Branche na "prywatnych" forkach
  • feat/new-functionality - Twoje zmiany na do danej funkcjonalności, to ta gałąź będzie potem PR do <master>/feat/new-functionality gdzie <master> to osoba prowadząca funkcjonalność lub origin jeśli takowej osoby nie ma.

W taki sposób masz ładnie wszystko rozłożone pomiędzy repozytoria dla różnych osób, gdzie nikt nie jest w stanie nikomu nic zepsuć. Dodatkowo zdecydowanie upraszcza to budowanie i releases, bo można łatwo skonfigurować CI do tego, by każdy commit na origin/master był deployowany na staging oraz by każdy tag był deployowany na produkcję.

0

super, dzięki :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1