Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Git - mini-szkolenie [PL]

Git - mini-szkolenie [PL]

Prezentacja z wewnętrznego mini-szkolenia z Gita w j. polskim przeprowadzonego dla Digital Fingerprints.

Piotr Wittchen

December 29, 2021
Tweet

More Decks by Piotr Wittchen

Other Decks in Programming

Transcript

  1. [email protected]fingerprints.digital
    2021.12.29

    View Slide

  2. Jak będzie wyglądało to szkolenie?

    View Slide

  3. Plan szkolenia
    ● Dobre praktyki pracy z Gitem
    ● Problemy podczas pracy z Gitem i rozwiązania
    ● Pytania dotyczące pozostałych problemów z Gitem

    View Slide

  4. Dobre praktyki pracy z Gitem
    ● Git Flow
    ● Konfiguracja i aliasy
    ● GUI vs. terminal
    ● Treść wiadomości w commicie
    ● Wiele commitów w trakcie developmentu
    ● Squash commitów na branchu przed PR
    ● Przegląd własnych zmian przed commitem
    ● Nie nadpisywanie historii w głównych branchach (develop i master)
    ● Tagowanie wersji w odpowiedni sposób

    View Slide

  5. Git Flow
    master
    develop
    feature-1
    bugfix-2
    v0.0.2
    v0.0.3-RC2
    hotfix-3
    v0.0.3-RC1
    v0.0.1
    --ff-only
    --no-ff

    View Slide

  6. Konfiguracja i aliasy
    ~/.gitignore_global
    ~/.gitconfig
    ~/.zshrc

    View Slide

  7. GUI vs. terminal

    View Slide

  8. Treść wiadomości w commicie
    Pamiętajmy, aby pisać dobre, szczegółowe i opisowe treści
    wiadomości w commitach. Pozwala to na łatwiejszą analizę logów,
    nawigowanie w historii, wyszukiwanie błędów i wycofywanie zmian.
    Zamiast komendy: git commit -m, możemy użyć: git commit.
    Linki:
    ● https://chris.beams.io/posts/git-commit/
    ● https://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message
    ● http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
    ● https://fatbusinessman.com/2019/my-favourite-git-commit
    ● https://github.com/torvalds/linux/pull/17
    ● https://github.com/pwittchen/craplog

    View Slide

  9. Squash commitów przed PR
    ● W trakcie developmentu możemy wykonywać wiele commitów do
    feature brancha
    ● Po zakończeniu developmentu, przed wystawieniem PR powinniśmy
    zesquashować wszystkie commity do jednego
    ● Pozwoli to zachować czystą i w miarę krótką historię oraz na łatwą
    nawigację po git logu i wycofywanie zmian w razie potrzeby
    ● Wyjątkiem od tej reguły jest sytuacja, w której wykonaliśmy wiele
    znaczących zmian w ramach jednego zadania i chcemy je wyraźnie
    rozdzielić osobnymi commitami

    View Slide

  10. Przegląd własnych zmian przed commitem
    git add -p

    View Slide

  11. Nie nadpisywanie historii w głównych branchach
    ● Nie powinniśmy zmieniać historii (git push --force) na głównych
    branchach (develop i master)
    ● Nadpisywanie historii głównych branchy może spowodować rozjazd
    historii u wszystkich developerów i problemy z dalszą pracą
    ● Nadpisywanie historii głównych branchy może spowodować utratę kodu
    lub historii jego zmian
    ● Nadpisywanie historii głównych branchy powinno być zablokowane w
    konfiguracji repozytorium (np. z poziomu Bitbucketa)

    View Slide

  12. Tagowanie wersji w odpowiedni sposób
    v1.2.3
    major
    minor
    patch
    breaking changes
    (major releases)
    new features
    (keeping backward compatibility)
    bug fixes
    (keeping backward compatibility)
    0.x.x
    Beta release (may be unstable)
    1.x.x-RC1
    Release Candidate (may be unstable)
    semantyczne wersjonowanie Jeśli to możliwe, powinniśmy
    automatyzować release do
    ECR/Artifactory w oparciu o tagi z Gita

    View Slide

  13. Problemy podczas pracy z Gitem i rozwiązania

    View Slide

  14. Pro tip
    Przykładowe rozwiązania to tylko propozycje!
    Dany problem można rozwiązać na wiele sposobów.

    View Slide

  15. Problem #1
    zrobienie squasha do jednego commita na swoim branchu,
    a potem rabase do developa już z tylko tym 1 commitem

    View Slide

  16. Problem #1 - proponowane rozwiązanie
    git checkout p1
    git rebase -i develop
    git add -A
    # otwierany jest edytor tekstu w terminalu
    p commit1 # p = pick
    s commit2 # s = squash
    s commit3
    # zapis zmian
    # otwierany jest edytor tekstu w terminalu
    git commit
    git checkout develop
    git pull
    git checkout p1
    git rebase develop

    View Slide

  17. Problem #2
    Co robić w sytuacji, jak mamy brancha z brancha, chcemy
    zesquashować zmiany z pierwszego brancha i połączyć je z
    drugim, ale tak, żeby się historia nie rozjechała

    View Slide

  18. Problem #2 - proponowane rozwiązanie
    # reprodukcja sytuacji
    git checkout develop
    git checkout -b p2.1
    # dokonujemy zmian
    git commit
    git commit
    git checkout -b p2.2
    # dokonujemy zmian
    git commit
    git commit
    # dalsze kroki
    git checkout p2.1
    git rebase -i develop
    # wykonujemy squasha do 1 commita
    git checkout p2.2
    git rebase -i develop
    # wykonujemy squasha do 1 commita
    git reset --soft HEAD~1
    git stash
    git checkout p2.1
    git stash pop
    git git add -A
    git commit
    # opcjonalnie robimy kolejny squash do 1 commita

    View Slide

  19. Problem #3
    Sytuacja, gdzie mamy już wypchnięte zesquashowane
    zmiany, a okazało się, że trzeba cofnąć zmiany z dwóch
    ostatnich commitow i wprowadzić nowe zmiany.

    View Slide

  20. Problem #3 - proponowane rozwiązanie
    # reprodukcja sytuacji
    git checkout develop
    git checkout -b p3.1
    git commit
    git commit
    git rebase -i develop
    # wykonujemy squasha do 1 commita
    git commit
    git push
    # dalsze kroki
    git reflog
    # znajdujemy commit przed squashem
    git checkout # np. a24c840
    git switch -c p3.2 # since git 2.23.0
    git reset --hard HEAD~2
    # wykonujemy nowe zmiany
    git commit
    git push
    # PR wykonujemy wtedy
    # z poziomu nowego brancha p3.2
    # usuwamy starego brancha
    git branch -D p3.1
    git push origin --delete p3.1

    View Slide

  21. Problem #4
    Mamy developa lokalnie, na którym robimy jakieś
    zmiany i później chcemy aby te zmiany znalazły się na
    nowym branchu, którego tworzymy z developa (albo jest
    już utworzony)

    View Slide

  22. Problem #4 - proponowane rozwiązanie
    # reprodukcja problemu
    git checkout develop
    # wykonujemy zmiany
    git commit
    git commit
    # dalsze kroki
    git reset --soft HEAD~2 # 2 = liczba commitów
    # do wycofania
    # alternatywna komenda względem powyższej
    git reset --soft origin/develop
    # powrót do stanu ze zdalnego developa
    # commity zostają wycofane
    # zmiany znajdują się w trybie staging
    # i nie są zacommitowane
    git checkout -b p4
    git commit

    View Slide

  23. Problem #5
    W czasie pracy na branchu z taska weszło sporo nowych commitów do developa. Chcemy już
    wystawić PRkę i robimy git rebase -i develop. Wtedy musimy osobno poprawiać konflikty z
    każdym commitem, który różni nas od developa. Mniej więcej tak:
    ● rebase trwa do momentu pierwszego konfliktu
    ● naprawiamy konflikty, dajemy git rebase --continue
    ● pojawiają się kolejne konflikty, bardzo często zbliżone do tych, które już poprawiliśmy
    ● To powoduje, że możemy wielokrotnie poprawiać ten sam kod.

    View Slide

  24. Problem #5 - proponowane rozwiązanie
    # reprodukcja problemu
    git checkout develop
    # wykonujemy zmiany
    git commit
    git commit
    git checkout p5
    # wykonujemy zmiany
    # w tych samych miejscach
    # co na developie
    git rebase -i develop
    # lub:
    git rebase develop
    # dalsze kroki
    # rozwiązanie konfliktów
    # w poszczególnych plikach
    # w edytorze lub IntelliJ/PyCharm
    git add -A
    git rebase --continue
    # konflikty powinny być rozwiązywane
    # w jednym miejscu tylko raz
    pro-tip:
    sytuacje tego typu nie powinny występować lub
    powinny występować rzadko, jeśli zadania będą
    odpowiednio podzielone lub rozwiązane
    sekwencyjnie po kolei i dwie osoby (lub więcej) nie
    będą modyfikować tych samych plików lub funkcji w
    tym samym czasie. Warto o tym pamiętać podczas
    planowania pracy i komunikować się na bieżąco
    w trakcie developmentu.

    View Slide

  25. Problem #6
    Kiedy pojawiają się commity typu
    “develop merged into develop”
    i co z tym zrobić?

    View Slide

  26. Problem #6 - proponowane rozwiązanie
    # reprodukcja problemu
    git checkout develop
    # wykonujemy zmiany
    git commit
    git commit
    # w międzyczasie zostały
    # wykonane zmiany w tych samych
    # plikach w tym samym miejscu,
    # w którym my coś zmienialiśmy
    git pull # = git fetch + git merge
    # dalsze kroki
    git reflog
    # znajdujemy commita
    # z naszymi zmianami
    git checkout
    git checkout -b p6
    # lub:
    git switch -c p6
    git checkout develop
    git reset --hard origin/master
    # tworzymy nowy PR
    # z naszymi zmianami
    # na nowym branchu

    View Slide

  27. Problem #7
    Konflikty wewnętrzne typu “sam ze sobą”
    Kiedy się pojawiają i jak ich uniknąć?

    View Slide

  28. Problem #7 - proponowane rozwiązanie
    Konflikty tego typu mogą wystąpić, gdy nadpisujemy historię za pomocą komend:
    git commit --amend lub git rebase w połączeniu z git pull
    Należy uważać, abyśmy nie mieli pomieszanej historii na zdalnych branchach z
    branchami lokalnymi, to wtedy powinniśmy uniknąć tego typu błędów.

    View Slide

  29. Problem #8
    Jak nawigować po historii Gita?

    View Slide

  30. Problem #8 - proponowane rozwiązanie
    git log --oneline --graph
    reference: https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git
    Ogólne zasady (rules of thumb):
    ● używamy ~ przez większość czasu do nawigacji wstecz
    ● używamy ^ na merge commitach, ponieważ mają dwóch lub więcej rodziców
    Mnemonika:
    ● tilde ~ liniowe występowanie i przejście wstecz w linii prostej
    ● caret ^ sugeruje interesujący segment drzewa lub fork tworzący wiele gałęzi

    View Slide

  31. Problem #8 - proponowane rozwiązanie, c.d.
    G H I J
    \ / \ /
    D E F
    \ | / \
    \ | / |
    \|/ /
    B C
    \ /
    \/
    A
    A = A^0
    B = A^ = A^1 = A~1
    C = A^2
    D = A^^ = A^1^1 = A~2
    E = B^2 = A^^2
    F = B^3 = A^^3
    G = A^^^ = A^1^1^1 = A~3
    H = D^2 = B^^2 = A^^^2 = A~2^2
    I = F^ = B^3^ = A^^3^
    J = F^2 = B^3^2 = A^^3^2
    reference: https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git

    View Slide

  32. Problem #9
    Jak ignorować pliki lokalnie?

    View Slide

  33. Problem #9 - proponowane rozwiązanie
    # ignorowanie plików lokalnie
    git update-index --assume-unchanged filename
    # zaprzestanie ignorowania plików lokalnie
    git update-index --no-assume-unchanged filename
    # wyświetlanie plików ignorowanych lokalnie
    git ls-files -v | grep “^[[:lower:]]”

    View Slide

  34. Problem #10
    Jak zresetować wszystkie niezacommitowane, zmiany
    tylko w jednym pliku lub przywrócić usunięty plik?

    View Slide

  35. Problem #10 - proponowane rozwiązanie
    # resetowanie WSZYSTKICH niezacommitowanych lokalnych zmian
    git reset --hard
    # resetowanie jednego zmienionego/usuniętego niezestagowanego pliku
    git checkout HEAD -- /path/to/file
    # przywracanie usuniętego pliku
    git checkout $(git rev-list -n 1 HEAD -- /path/to/file)^ -- path/to/file

    View Slide

  36. Pozostałe (niewymienione) pytania/problemy?

    View Slide

  37. Dziękuję za uwagę
    [email protected]fingerprints.digital
    2021.12.29

    View Slide