{"id":3589,"date":"2017-01-30T10:55:38","date_gmt":"2017-01-30T09:55:38","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=3589"},"modified":"2023-02-01T12:52:53","modified_gmt":"2023-02-01T11:52:53","slug":"wspolpracowac-z-gitem","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/wspolpracowac-z-gitem\/","title":{"rendered":"Wsp\u00f3\u0142pracowa\u0107 z gitem"},"content":{"rendered":"\n<p>Git jest systemem kontroli wersji. Zapisuje historie zmian w \u015bledzonym katalogu.<br>W kilku etapach postaram si\u0119 przybli\u017cy\u0107 jak wygl\u0105da praca z gitem i jakimi mechanizmami si\u0119 rz\u0105dzi.<\/p>\n\n\n\n<p>W artykule opisuj\u0119 w jaki spos\u00f3b git przechowuje dane o zmianach, jakie s\u0105 tego implikacje i w jaki spos\u00f3b dzia\u0142aj\u0105 poszczeg\u00f3lne komendy.<\/p>\n\n\n\n<p>Tre\u015b\u0107 jest dedykowana dla os\u00f3b, kt\u00f3re maj\u0105 podstawowe do\u015bwiadczenie z gitem i chc\u0105 uzupe\u0142ni\u0107 swoj\u0105 wiedz\u0119.<\/p>\n\n\n\n<p>Zaczynamy!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">W PIGU\u0141CE O STRUKTURZE BAZY DANYCH<\/h3>\n\n\n\n<p>Podstawowe za\u0142o\u017cenia:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>repozytorium to katalog (.git), w kt\u00f3rym jest baza danych<\/li><li>git u\u017cywa struktur niezmiennych (immutable structures)<\/li><li>w trakcie pracy mo\u017cemy modyfikowa\u0107 tylko wska\u017aniki \u2013 TAGI i BRANCHE<\/li><li>pojedynczy commit(zapis) jest to zapis stanu \u015bledzonego katalogu<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Repozytorium<\/h4>\n\n\n\n<p>Po sklonowaniu&nbsp;<em>git clone<\/em>&nbsp;lub inicjacji nowego repozytorium&nbsp;<em>git init<\/em>&nbsp;tworzony jest katalog o nazwie&nbsp;<em>.git<\/em>&nbsp;(kropka git) w kt\u00f3rym znajduje si\u0119 baza danych gita. Repozytoria zdalne (te z kt\u00f3rymi si\u0119 synchronizuj\u0105 u\u017cytkownicy) s\u0105 r\u00f3wnie\u017c tworzone poleceniem&nbsp;<em>git init \u2013bare<\/em>. W takim przypadku nie wyst\u0119puje katalog roboczy, a w jego miejscu jest umieszczona baza danych \u2013 czyli to samo co jest lokalnie w .git .<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Struktury niezmienne (immutable structures)<\/h4>\n\n\n\n<p>Git zapisuje w repozytorium kopie wszystkich \u015bledzonych zasob\u00f3w. Podstawow\u0105 operacj\u0105 jest&nbsp;<em>git commit<\/em>&nbsp;czyli zapis katalogu roboczego. Podczas tej operacji tworzona jest seria wpis\u00f3w, w bazie gita, zawieraj\u0105ca m.in. kopie zmienionych plik\u00f3w, opis zmian. Ka\u017cdy wpis w bazie danych jest identyfikowany swoim 'skr\u00f3tem\u2019 (hashem). Skr\u00f3t jest tworzony w oparciu o zawarto\u015b\u0107 pojedynczego wpisu. W praktyce oznacza to, \u017ce nie wyst\u0119puj\u0105 dwa r\u00f3\u017cne wpisy do bazy gita, kt\u00f3re maj\u0105 taki sam skr\u00f3t.<\/p>\n\n\n\n<p>Przyk\u0142adowy skr\u00f3t:&nbsp;<em>aaa43c379d7b32606f8e8a4fb7248747821c2c27<\/em>.<\/p>\n\n\n\n<p>Historia zmian w gitcie jest zapisywana jako lista 'commit\u00f3w\u2019.<\/p>\n\n\n\n<p>Przyk\u0142adowy commit z bazy danych gita (<em>\u00a0git cat-file<\/em>\u00a0pokazuje tre\u015b\u0107 wpisu z bazy danych):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git cat-file -p HEAD\ntree 51c68a455640c831d2a0cf0103b8f76484df9bb9\nparent aaa43c379d7b32606f8e8a4fb7248747821c2c27\nauthor Maciej Aleksandrowicz &amp;lt;maleksandrowicz@pl.sii.eu&gt; 1483435432 +0100\ncommitter Maciej Aleksandrowicz &amp;lt;maleksandrowicz@pl.sii.eu&gt; 1483435432 +0100\nNowy commit\n<\/pre><\/div>\n\n\n<p>Prawie ka\u017cdy commit (z wyj\u0105tkiem pierwszego) zawiera pole 'parent\u2019, kt\u00f3re wskazuje na poprzedzaj\u0105cy wpis. W ten spos\u00f3b jest tworzona lista zmian.<\/p>\n\n\n\n<p>Efekt z tego taki, \u017ce nie mo\u017cna modyfikowa\u0107 ju\u017c dodanych commit\u00f3w (nie oznacza to, \u017ce nie da si\u0119 cofa\u0107 pomy\u0142kowo dodanych zmian), poniewa\u017c ka\u017cda zmiana zmieni\u0142aby jego skr\u00f3t i 'przerwa\u0142a\u2019 list\u0119.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Mo\u017cemy modifikowa\u0107 tylko wska\u017aniki \u2013 TAGI i BRANCHE<\/h4>\n\n\n\n<p>Skoro dodajemy tylko nowe commity, to pojawia si\u0119 pytanie \u2013 gdzie jest zapisany skr\u00f3t najnowszego commita?<\/p>\n\n\n\n<p>Tu pojawiaj\u0105 si\u0119 BRANCHE (ga\u0142\u0119zie) i TAGI (znaczniki). S\u0105 to jedyne elementy, kt\u00f3re s\u0105 zmienne w bazie danych gita. Ka\u017cdy tag i branch jest plikiem w bazie gita (<em>.git\/refs\/heads<\/em>&nbsp;i&nbsp;<em>.git\/refs\/tags<\/em>), kt\u00f3rego tre\u015bci\u0105 jest skr\u00f3t commita.<\/p>\n\n\n\n<p>Praca na ga\u0142\u0119zi 'master\u2019, oznacza \u017ce ka\u017cda kolejna zmiana b\u0119dzie w odniesieniu do commita zapisanego w pliku\u00a0<em>.git\/refs\/heads\/master<\/em>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ cat .git\/refs\/heads\/master\nc29cc78766e9aa6c17b53f9a40f5427c93054956\n<\/pre><\/div>\n\n\n<p>TAGI od BRANCHE\u2019y r\u00f3\u017cni\u0105 si\u0119 tylko tym, \u017ce nie s\u0105 modyfikowane. S\u0142u\u017c\u0105 do oznaczenia wa\u017cnych commit\u00f3w.<br>Mo\u017cna je po prostu utworzy\u0107 i w razie potrzeby usun\u0105\u0107.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Pojedynczy commit jest to zapis stanu \u015bledzonego katalogu<\/h4>\n\n\n\n<p>Ka\u017cdy commit ma w tre\u015bci pole 'tree\u2019. Jest to wska\u017anik na inny plik w bazie danych, kt\u00f3ry zawiera opis katalogu w repozytorium.<\/p>\n\n\n\n<p>Przyk\u0142adowa tre\u015b\u0107 wpisu 'tree\u2019:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git cat-file -p 51c68a455640c831d2a0cf0103b8f76484df9bb9\n100644 blob 5f44efa8e71bfca2d78f403f9d57898152a1effc    git.txt\n<\/pre><\/div>\n\n\n<p>Tre\u015b\u0107 pliku 'tree\u2019 to lista plik\u00f3w i katalog\u00f3w (innych plik\u00f3w tree) oraz ich odpowiednie skr\u00f3ty. Kiedy zmieniana jest tre\u015b\u0107 pliku lub struktura katalogu (np. dodanie nowego pliku, zmiana nazwy podkatalogu), zmianie ulega r\u00f3wnie\u017c jego skr\u00f3t. Wynika z tego, \u017ce jakakolwiek zmiana w repozytorium powoduje utworzenie nowego pliku 'tree\u2019 opisuj\u0105cego ca\u0142\u0105 struktur\u0119 katalog\u00f3w.<br>Nast\u0119pstwem tego podej\u015bcia jest brak mo\u017cliwo\u015bci zsynchronizowania tylko cz\u0119\u015bci repozytorium.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">PODSTAWOWE OPERACJE<\/h3>\n\n\n\n<p><em>Wi\u0119kszo\u015b\u0107 program\u00f3w oferuj\u0105cych interfejs graficzny (np. TortoiseGIT, SourceTree) utrzymuje podobne nazewnictwo jak nazwy komend. Interfejsy graficzne s\u0105 nak\u0142adk\u0105 na gita z linii polece\u0144.<\/em><\/p>\n\n\n\n<p>W czasie pracy z gitem wyst\u0119puj\u0105 2 obszary po kt\u00f3rych si\u0119 poruszamy: repozytorium i katalog roboczy:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>katalog roboczy to miejsce, w kt\u00f3ry znajduje si\u0119 repozytorium (katalog .git) i pliki \u015bledzone przez git<\/li><li>repozytorium jest to baza danych w kt\u00f3rej zapisywany jest stan katalogu roboczego w momencie commita, warto\u015bci wska\u017anik\u00f3w (branche i tagi), pliki konfiguracyjne, wska\u017aniki na zdalne repozytoria (remote)<\/li><\/ul>\n\n\n\n<p>Praca z gitem sprowadza si\u0119 do wykonania zapis stanu katalogu roboczego (<em>git commit<\/em>) i synchronizacji lokalnego repozytorium ze zdalnym (<em>git push\/pull\/fetch<\/em>).<br>Pracuj\u0105c z gitem, ka\u017cdy u\u017cytkownik zarz\u0105dza lokalnym repozytorium, tworzonym poleceniem&nbsp;<em>git clone<\/em>. Takie repozytorium jest zsynchronizowane ze zdalnym repozytorium (remote).<br>Synchronizacja oznacza, \u017ce zmiany utworzone w lokalnej bazie danych s\u0105 wysy\u0142ane do zdalnego repozytorium, a zmiany ze zdalnego repozytorium, nak\u0142adane na lokalne. Dzi\u0119ki temu mo\u017cliwa jest wsp\u00f3lna praca wielu u\u017cytkownik\u00f3w.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">PRACA Z LINI\u0104 POLECE\u0143<\/h3>\n\n\n\n<p><strong>W skr\u00f3cie:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>git help<\/em>&nbsp;\u2013 uruchamia stron\u0119 z dokumentacj\u0105 ka\u017cdej komendy w git. Np. git help add, uruchamia instrukcje komendy 'git add\u2019<\/li><li><em>git status<\/em>&nbsp;\u2013 pokazuje obecny stan katalogu roboczego<\/li><li><em>git log<\/em>&nbsp;\u2013 pokazuje list\u0119 zmian w repozytorium<\/li><li><em>git add<\/em>&nbsp;\u2013 dodaje pliki do indeksu(etapu przygotownia commita) (flaga -A dodaje r\u00f3wnie\u017c usuni\u0119te pliki)<\/li><li><em>git commit<\/em>&nbsp;\u2013 zapisuje zmiany z indeksu do bazy danych<\/li><li><em>git push<\/em>&nbsp;\u2013 wysy\u0142a zmiany do zdalnego repozytorium<\/li><li><em>git reset<\/em>&nbsp;\u2013 zmiana wska\u017anika brancha<\/li><li><em>git clean<\/em>&nbsp;\u2013 usuwanie nie\u015bledzonych plik\u00f3w<\/li><li><em>git checkout<\/em>&nbsp;\u2013 zmienia aktualny branch, zmienia stan katalogu roboczego np. zmienia warto\u015b\u0107 katalogu na wersj\u0119 z innego brancha<\/li><li><em>git pull<\/em>&nbsp;\u2013 pobiera zmiany ze zdalnego repozytorium i wykonuje merge lub rebase<\/li><li><em>git fetch<\/em>&nbsp;\u2013 pobiera zmiany ze zdalnego repozytorium, ale nie nanosi ich na katalog roboczy<\/li><li><em>git stash<\/em>&nbsp;\u2013 tworzy commit obecnych zmian i przywraca katalog roboczy do stanu z repozytorium (od\u0142o\u017cenie zmian na p\u00f3\u0142k\u0119)<\/li><li><em>git rebase<\/em>&nbsp;\u2013 wykonuje ponownie seri\u0119 commit\u00f3w, ale na innej ga\u0142\u0119zi. Ma wiele zastosowa\u0144<\/li><li><em>git cherry-pick<\/em>&nbsp;\u2013 tworzy commit ze zmianami z innego commita<\/li><li><em>git clone<\/em>&nbsp;\u2013 tworzy repozytorium na podstawie innego<\/li><li><em>git init<\/em>&nbsp;\u2013 tworzy nowe, puste repozytorium<\/li><\/ul>\n\n\n\n<p>Obecnie katalog roboczy jest zsynchronizowany z repozytorium \u2013 wskazuje to polecenie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git status\nOn branch master\nnothing to commit, working tree clean\n<\/pre><\/div>\n\n\n<p><em>working tree clean<\/em>&nbsp;\u2013 czyli katalog roboczy nie ma oczekuj\u0105cych zmian<\/p>\n\n\n\n<p>Po zmodyfikowaniu pliku git.txt:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git status\nOn branch master\nChanges not staged for commit:\n  (use &quot;git add ...&quot; to update what will be committed)\n  (use &quot;git checkout -- ...&quot; to discard changes in working directory)\n\n        modified:   git.txt\n\nno changes added to commit (use &quot;git add&quot; and\/or &quot;git commit -a&quot;)\n<\/pre><\/div>\n\n\n<p>Przygotowanie commita sk\u0142ada si\u0119 z 2 etap\u00f3w:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>dodanie plik\u00f3w do indeksu (oznaczenie ich do zapisu)<\/li><li>utworzenie commita<\/li><\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Dodanie plik\u00f3w do indeksu<\/h4>\n\n\n\n<p>Powy\u017cej git wskazuje, \u017ce plik git.txt nie jest oznaczony do zapisu (Changes not staged for commit).<br>polecenie\u00a0<em>git add git.txt<\/em>\u00a0dopisuje go do indeksu. Teraz\u00a0<em>git status<\/em>\u00a0wskazuje:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git status\nOn branch master\nChanges to be committed:\n  (use &quot;git reset HEAD ...&quot; to unstage)\n\n        modified:   git.txt\n<\/pre><\/div>\n\n\n<p>Polecenie\u00a0<em>git add<\/em>\u00a0doda\u0142o plik git.txt do indeksu.<br><strong>WA\u017bNE<\/strong><br><em>polecenie 'git add\u2019 tworzy kopi\u0119 pliku git.txt w momencie kiedy by\u0142 uruchomiony.<br>Oznacza to, \u017ce kiedy po 'git add\u2019 zrobi\u0119 zmian\u0119 w pliku git.txt, nie b\u0119dzie ona widoczna w commitcie (chyba, \u017ce ponownie wpisz\u0119 'git add git.txt\u2019), a 'git status\u2019 poka\u017ce<\/em>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git status\nOn branch master\nChanges to be committed:\n  (use &quot;git reset HEAD ...&quot; to unstage)\n\n\t\tmodified:   git.txt\n\nChanges not staged for commit:\n  (use &quot;git add ...&quot; to update what will be committed)\n  (use &quot;git checkout -- ...&quot; to discard changes in working directory)\n\n\t\tmodified:   git.txt\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Utworzenie commita<\/h4>\n\n\n\n<p>polecenie\u00a0<em>git commit -m \u201eprzykladowy commit\u201d<\/em>\u00a0utworzy commit o nazwie 'przykladowy commit\u2019.<br>Uruchomienie\u00a0<em>git commit<\/em>\u00a0bez dodatkowego parametru uruchomi domy\u015blny edytor tekstowe, w kt\u00f3rym nale\u017cy wprowadzi\u0107 nazw\u0119.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git commit -m &quot;przykladowy commit&quot;\n&#x5B;master 8de15f5] przykladowy commit\n 1 file changed, 72 insertions(+), 2 deletions(-)\n<\/pre><\/div>\n\n\n<p>Kolejnym krokiem jest synchronizacja ze zdalnym repozytorium.<br>Polecenie\u00a0<em>git pull<\/em>\u00a0pobiera zdalne zmiany.<br>Je\u015bli w mi\u0119dzyczasie zdalne repozytorium zosta\u0142o zmodyfikowane automatycznie tworzy 'merge\u2019 czyli z\u0142\u0105czenie dw\u00f3ch ga\u0142\u0119zi. W takim przypadku uruchamia si\u0119 edytor (jak w przypadku\u00a0<em>git commit<\/em>\u00a0bez dodatkowego parametru) z opisem zmiany. W tym momencie mog\u0105 wyst\u0119powa\u0107 konflikty (conflicts). Merge\/Rebase i konflikty s\u0105 opisane poni\u017cej.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git pull\nremote: Counting objects: 3, done.\nremote: Compressing objects: 100% (2\/2), done.\nremote: Total 3 (delta 1), reused 0 (delta 0)\nUnpacking objects: 100% (3\/3), done.\nFrom C:\/Users\/maleksandrowicz\/Desktop\/blogersii\/..\/blogersiiremote\n   8de15f5..2634d92  master     -&gt; origin\/master\nUpdating 8de15f5..2634d92\nFast-forward\n git.txt | 19 ++++++++++++++++++-\n 1 file changed, 18 insertions(+), 1 deletion(-)\n<\/pre><\/div>\n\n\n<p>Kiedy lokalne repozytorium jest zsynchronizowane, mo\u017cna 'wypchn\u0105\u0107\u2019 lokalne zmiany do zdalnego repozytorium poleceniem\u00a0<em>git push<\/em>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git push\nCounting objects: 3, done.\nDelta compression using up to 8 threads.\nCompressing objects: 100% (2\/2), done.\nWriting objects: 100% (3\/3), 555 bytes | 0 bytes\/s, done.\nTotal 3 (delta 1), reused 0 (delta 0)\nTo C:\/Users\/maleksandrowicz\/Desktop\/blogersii\/..\/blogersiiremote\n   2634d92..3b13d1b  master -&gt; master\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Branche i tagi<\/h4>\n\n\n\n<ul class=\"wp-block-list\"><li>na katalog roboczy zawsze wskazuje branch HEAD<\/li><li>nowy branch tworzy si\u0119 poleceniem&nbsp;<em>git branch NAZWA<\/em>. Nowy branch wskazuje commit wskazywany przez HEAD<\/li><li><em>git tag<\/em>&nbsp;jest odpowiednikiem&nbsp;<em>git branch<\/em>&nbsp;dla tag\u00f3w<\/li><li><em>git checkout NAZWA<\/em>&nbsp;zmienia aktywny branch<\/li><li><em>git checkout -b NAZWA<\/em>&nbsp;tworzy branch i ustawia go jako aktywny<\/li><li><em>git branch -d NAZWA<\/em>&nbsp;usuwa branch o ile nie pozostawi 'osieroconych\u2019 commit\u00f3w (czyli jest zmergowany)<\/li><li><em>git branch -D NAZWA<\/em>&nbsp;(du\u017ce d) usuwa branch niezale\u017cnie czy pozostawi commity<\/li><li><em>git push -u origin NAZWA<\/em>&nbsp;tworzy w zdalnym repozytorium 'origin\u2019 branch NAZWA i automatycznie kojarzy lokaln\u0105 ga\u0142\u0105\u017a NAZWA z origin\/NAZWA<\/li><li><em>git push origin :NAZWA<\/em>&nbsp;(dw\u00f3kropek przed nazw\u0105) usuwa branch ze zdalnego repozytorium 'origin\u2019<\/li><\/ul>\n\n\n\n<p><em>git branch -a<\/em>\u00a0pokazuje list\u0119 wszystkich ga\u0142\u0119zi w repozytorium.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git branch -a\n* master\n  remotes\/origin\/HEAD -&gt; origin\/master\n  remotes\/origin\/master\n<\/pre><\/div>\n\n\n<p>Branch 'master\u2019 ma swoj\u0105 reprezentacj\u0119 w zdalnym repozytorium (nazwane 'origin\u2019) jako 'origin\/master\u2019.<\/p>\n\n\n\n<p>origin\/master wskazuje na stan zdalnego repozytorium.<br>W momencie kiedy uruchamiany jest&nbsp;<em>git fetch<\/em>&nbsp;lub&nbsp;<em>git pull<\/em>, pobierane s\u0105 zmiany ze zdalnego repozytorium i przesuwana jest ga\u0142\u0105\u017a origin\/master.<\/p>\n\n\n\n<p>Lokalne zmiany s\u0105 utworzone w ga\u0142\u0119zi master (\u2019master\u2019 i 'origin\/master\u2019 s\u0105 to 2 r\u00f3\u017cne ga\u0142\u0119zie). \u017beby mo\u017cna by\u0142o doda\u0107 lokalne zmiany do zdalnego repozytorium, operacja\u00a0<em>git pull<\/em>\u00a0wykonuje z\u0142\u0105czenie lokalnej i zdalnej ga\u0142\u0119zi. Efektem z\u0142\u0105czenia (merge\u2019a) jest nowy 'specjalny\u2019 commit, kt\u00f3ry ma 2 ga\u0142\u0119zie nadrz\u0119dne.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$ git cat-file -p HEAD\ntree b0e26f6ea15223f9bf51edaa5b61611a5bd046ef\nparent 8eb8f89082f9024fed980055145b8fce3521fa61\nparent 4fcbcc435882f92e807d85f3c9e59ec8ba3beeca\nauthor Maciej Aleksandrowicz &amp;lt;maleksandrowicz@pl.sii.eu&gt; 1483446754 +0100\ncommitter Maciej Aleksandrowicz &amp;lt;maleksandrowicz@pl.sii.eu&gt; 1483446754 +0100\n\nMerge branch &#039;X&#039;\n<\/pre><\/div>\n\n\n<p>Po z\u0142\u0105czeniu ga\u0142\u0119zi mo\u017cna wypchn\u0105\u0107 zmiany do zdalnego repozytorium.<br>Z punktu widzenia zdalnego repozytorium, je\u017celi zmieniana jest np. master, to przyjmowane s\u0105 jedynie takie zmiany, kt\u00f3re dodadz\u0105(mo\u017cna do niej doda\u0107 tylko nowe commity).<br>Ga\u0142\u0119zie to wska\u017aniki do commit\u00f3w.<\/p>\n\n\n\n<p><strong>Przyk\u0142ad:<\/strong><\/p>\n\n\n\n<p>Zdalne repozytorium sk\u0142ada si\u0119 z commit\u00f3w X, Y, Z. Master wskazuje na commit Z.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">(zdalne)\n|Z - [master]\n|Y\n|X<\/pre>\n\n\n\n<p>U\u017cytkownik synchronizowa\u0142 si\u0119 z tym repozytorium dawno temu, kiedy ostatnim commitem by\u0142 Y.<br>Nast\u0119pnie doda\u0142 do niego lokalnie commit Y1:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n(lokalne)\n|Y1 - &#x5B;master]\n|Y - &#x5B;origin\/master]\n|X\n<\/pre><\/div>\n\n\n<p>Kiedy u\u017cytkownik uruchamia&nbsp;<em>git push<\/em>&nbsp;zdalne repozytorium zwraca b\u0142\u0105d, poniewa\u017c master w zdalnym repozytorium zmieni\u0142by si\u0119 z 'Z\u2019 na 'Y1\u2032, czyli przepad\u0142by commit 'Z\u2019. Mo\u017cna dodawa\u0107 tylko nowe commity do ga\u0142\u0119zi (wyj\u0105tkiem jest flaga -f do push. Jej niew\u0142a\u015bciwe wykorzystanie mo\u017ce rozsynchronizowa\u0107 repozytoria).<\/p>\n\n\n\n<p>W tym momencie u\u017cytkownik uruchamia\u00a0<em>git pull<\/em>, kt\u00f3re pobiera zmian\u0119 'Z\u2019 i aktualizuje branch origin\/master:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n(lokalnie)\n|Y1 - &#x5B;master]    |Z - &#x5B;origin\/master]\n|Y----------------\/\n|X\n<\/pre><\/div>\n\n\n<p>W zale\u017cno\u015bci od trybu wywo\u0142ania&nbsp;<em>git pull<\/em>:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>(domy\u015blnie) wykona merge ga\u0142\u0119zi master i origin\/master:<\/li><\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n|MERGE - &#x5B;master]&#x5B;origin\/master]\n|   \\\n|Y1 Z\n|   \/\n|  \/\n|Y \n|X\n<\/pre><\/div>\n\n\n<p>W tym momencie\u00a0<em>git push<\/em>\u00a0zadzia\u0142a, bo z punktu widzenia repozytorium, do ga\u0142\u0119zi master zosta\u0142 dodany nowy commit (nad Z pojawi\u0142 si\u0119 commit MERGE).<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>(<em>git pull \u2013rebase<\/em>) utworzy lustrzane commity(rebase), kt\u00f3re b\u0119d\u0105 zaczyna\u0142y si\u0119 z ga\u0142\u0119zie origin\/master:<\/li><\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n|!Y1 &#x5B;master]&#x5B;origin\/master]\n|Z   |Y1 (na ten commit nie wskazuje ju\u017c \u017caden branch)\n|Y---\/\n|X\n<\/pre><\/div>\n\n\n<p>!Y1 \u2013 to commit z przeniesieniem zmian z Y1, ale utworzonych na podstawie stanu z commita Z. Rebase tworzy commity o takiej samej nazwie co oryginalne.\u00a0<em>Wykrzyknika w !Y1 u\u017cy\u0142em, \u017ceby zasygnalizowa\u0107, \u017ce to jest nowy commit<\/em><\/p>\n\n\n\n<p>Podobnie jak w powy\u017cszym przypadku, zdalne repozytorium widzi jedynie jeden nowy commit i push si\u0119 powiedzie.<\/p>\n\n\n\n<p><strong>WARTO WIEDZIE\u0106<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>polecenie&nbsp;<em>git fetch<\/em>&nbsp;pobiera jedynie zmiany ze zdalnego repozytorium i modyfikuje ga\u0142\u0119zie origin\/*,<br>w efekcie polecenie&nbsp;<em>git pull<\/em>&nbsp;jest najcz\u0119\u015bciej r\u00f3wnoznaczne z&nbsp;<em>git fetch<\/em>,<br><em>git merge<\/em>,<br>a polecenie&nbsp;<em>git pull \u2013rebase<\/em>&nbsp;jest najcz\u0119\u015bciej r\u00f3wnoznaczne z&nbsp;<em>git fetch<\/em>,&nbsp;<em>git rebase<\/em><\/li><li>W przypadku kiedy uruchamiany jest&nbsp;<em>git pull<\/em>, a nie ma lokalnie zmian do wypchni\u0119cia, git automatycznie przesunie lokaln\u0105 ga\u0142\u0105\u017a na zdaln\u0105. Taka operacja nazywa si\u0119 'fast-forward\u2019. W takiej sytuacji&nbsp;<em>git merge<\/em>&nbsp;i&nbsp;<em>git rebase<\/em>&nbsp;zadzia\u0142aj\u0105 identycznie.<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">KONFLIKTY<\/h3>\n\n\n\n<p>Do tej pory artyku\u0142 traktowa\u0142 gita jako baz\u0119 danych przechowuj\u0105c\u0105 r\u00f3\u017cne stany katalogu roboczego. Jednak poza sk\u0142adowaniem samych plik\u00f3w, analizowana jest ich tre\u015b\u0107. Podczas \u0142\u0105czenia synchronizacji mog\u0105 wyst\u0119powa\u0107 sytuacje, w kt\u00f3rych dw\u00f3ch u\u017cytkownik\u00f3w wykona\u0142o zmiany w tym samym pliku. Taka sytuacja jest nazywana konfliktem.<\/p>\n\n\n\n<p>Podczas operacji 'rebase\/merge\/cherry-pick\u2019 tworzone s\u0105 nowe commity na podstawie ju\u017c istniej\u0105cych.<br>Kiedy oka\u017ce si\u0119, \u017ce dwa commity zmieni\u0142y ten sam zas\u00f3b, git pr\u00f3buje rozwi\u0105za\u0107 konflikt. W przypadku plik\u00f3w tekstowych, wykonywane jest por\u00f3wnanie.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>je\u017celi inne cz\u0119\u015bci pliku zosta\u0142y zmienione przez oba commity, konflikt jest rozwi\u0105zywany automatycznie<\/li><li>je\u017celi zmienione cz\u0119\u015bci pliku tekstowego si\u0119 pokrywaj\u0105 lub zmiana nast\u0105pi\u0142a w pliku nie tekstowym, konflikt pozostaje do rozwi\u0105zania przez u\u017cytkownika<br>W takim momencie operacja si\u0119 zatrzymuje, a pliki kt\u00f3re s\u0105 podmiotami konfliktu, s\u0105 odpowiednio oznaczone (widoczne w&nbsp;<em>git status<\/em>).<\/li><\/ul>\n\n\n\n<p>Rozwi\u0105zaniem konfliktu jest doprowadzenie plik\u00f3w do oczekiwanego stanu i dodanie ich do 'indeksu\u2019 czyli&nbsp;<em>git add<\/em>.<\/p>\n\n\n\n<p>Po rozwi\u0105zaniu wszystkich konflikt\u00f3w, w zale\u017cno\u015bci od scenariusza nale\u017cy uruchomi\u0107:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>merge \u2013&nbsp;<em>git commit<\/em><\/li><li>rebase \u2013&nbsp;<em>git rebase \u2013continue<\/em><\/li><li>cherry-pick \u2013&nbsp;<em>git cherry-pick \u2013continue<\/em><\/li><\/ul>\n\n\n\n<p>Je\u017celi z jakiego\u015b powodu nie mo\u017cna rozwi\u0105za\u0107 konfliktu, to operacje rebase\/cherry-pick\/merge mo\u017cna przerwa\u0107 odpowiednio poleceniami:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>merge \u2013&nbsp;<em>git reset \u2013hard<\/em><\/li><li>rebase \u2013&nbsp;<em>git rebase \u2013abort<\/em><\/li><li>cherry-pick \u2013&nbsp;<em>git cherry-pick \u2013abort<\/em><\/li><\/ul>\n\n\n\n<p>W przypadku merge\u2019a, ekran konfliktu automatycznie przerywa operacje, wi\u0119c \u017ceby cofn\u0105\u0107 si\u0119 do stanu z przed merge\u2019a nale\u017cy zresetowa\u0107 katalog roboczy do stanu z repozytorium 'git reset \u2013hard\u2019.<\/p>\n\n\n\n<p>Kiedy w tekstowym pliku pojawia si\u0119 konflikt, kt\u00f3rego git nie potrafi automatycznie rozwi\u0105za\u0107, dodawane s\u0105 w nim znaczniki. Np. w przypadku merge\u2019a z ga\u0142\u0119zi\u0105 KONFLIKT pojawi\u0142o si\u0119:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD\nINNY TEKST, KT\u00d3RY SPOWODUJE KONFLIKT\n=======\nTen tekst powoduje konflikt\n&gt;&gt;&gt;&gt;&gt;&gt;&gt; KONFLIKT\n<\/pre><\/div>\n\n\n<p>od '&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD\u2019 do '=======\u2019 to zmiany w obecnej ga\u0142\u0119zi, od '=======\u2019 do \u2019&gt;&gt;&gt;&gt;&gt;&gt;&gt; KONFLIKT\u2019 to zmiany w mergowanej ga\u0142\u0119zi, gdzie KONFLIKT jest nazw\u0105 ga\u0142\u0119zi.<\/p>\n\n\n\n<p>Od u\u017cytkownika zale\u017cy jak b\u0119dzie wygl\u0105da\u0142 ostatecznie plik. Te znaczniki s\u0105 tylko podpowiedzi\u0105 i nic nie stoi na przeszkodzie, \u017ceby w takim stanie doda\u0107 plik przez&nbsp;<em>git add<\/em>&nbsp;(czego nie polecam, a co si\u0119 czasami zdarza w po\u015bpiechu) i w efekcie umie\u015bci\u0107 w repozytorium.<\/p>\n\n\n\n<p>W praktyce konflikty s\u0105 rozwi\u0105zywane za pomoc\u0105 oprogramowania, kt\u00f3re pozwala wybra\u0107 wersj\u0119, niemniej warto zapami\u0119ta\u0107, \u017ce przez&nbsp;<em>git add<\/em>&nbsp;oznaczamy ju\u017c poprawiony plik.<\/p>\n\n\n\n<p><strong>WA\u017bNE<\/strong><br>W przypadku konfliktu w trakcie rebase, kolejno\u015b\u0107 ga\u0142\u0119zi jest odwr\u00f3cona. Rebase jest wykonywany z punktu widzenia docelowej ga\u0142\u0119zi, na kt\u00f3r\u0105 s\u0105 nak\u0142adane ponownie poszczeg\u00f3lne commity. W takim przypadku, HEAD b\u0119dzie wskazywa\u0142 na t\u0119 ga\u0142\u0105\u017a, a nak\u0142adane zmiany b\u0119d\u0105 oznaczone jako obce. Jest to cz\u0119sty pow\u00f3d powstawania b\u0142\u0119d\u00f3w podczas synchronizacji.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">POPRAWIANIE COMMIT\u00d3W<\/h3>\n\n\n\n<p>W trakcie pracy na pewno zdarzy si\u0119 pomy\u0142kowo utworzony commit lub wypchni\u0119cie zmian z b\u0142\u0119dami.<\/p>\n\n\n\n<p><em>git revert<\/em>&nbsp;powoduje odwr\u00f3cenie zmian wybranego commita. Operacja tworzy nowy commit, kt\u00f3ry przywraca zmodyfikowane uprzednio pliki. Trzeba pami\u0119ta\u0107, \u017ce jest to kolejny commit i nale\u017cy go wypchn\u0105\u0107.<\/p>\n\n\n\n<p>Je\u017celi commit zosta\u0142 utworzony z b\u0142\u0119dem i nie zosta\u0142 jeszcze wypchni\u0119ty, mo\u017cna zastosowa\u0107 polecenia:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>git reset<\/em><\/li><li><em>git commit \u2013amend<\/em><\/li><li><em>git rebase -i<\/em><\/li><\/ul>\n\n\n\n<p><em>git reset NAZWABRANCHA<\/em>&nbsp;ustawia aktualny branch na commit wskazany przez NAZWABRANCHA. W przypadku u\u017cycia flagi \u2013hard, wszystkie lokalne zmiany z katalogu roboczego (r\u00f3wnie\u017c z indeksu) s\u0105 usuwane.<\/p>\n\n\n\n<p><strong>WARTO WIEDZIE\u0106<\/strong><br><em>git dzia\u0142a wy\u0142\u0105cznie na plikach i katalogach, kt\u00f3re s\u0105 przez niego \u015bledzone. Uruchomienie polecenia 'git reset \u2013hard\u2019 nie usunie plik\u00f3w, kt\u00f3re nie s\u0105 dodane do repozytorium. S\u0142u\u017cy do tego polecenie 'git clean\u2019<\/em><\/p>\n\n\n\n<p>Reset oferuje opcje : soft\/mixed(domy\u015blny)\/hard\/keep\/merge ( po wyczerpuj\u0105ce informacje odsy\u0142am do&nbsp;<em>git help reset<\/em>)<\/p>\n\n\n\n<p>Polecenie&nbsp;<em>git reset \u2013soft HEAD~1<\/em>&nbsp;cofa commit do etapu zaraz przed ostatnim poleceniem&nbsp;<em>git commit<\/em>.<br>HEAD~1 oznacza, \u017ceby przenie\u015b\u0107 si\u0119 do commita o jeden wcze\u015bniej ni\u017c HEAD.<\/p>\n\n\n\n<p>Polecenie&nbsp;<em>git commit \u2013amend<\/em>&nbsp;zast\u0119puje obecny najnowszy commit. Polecenie wygodne w przypadku liter\u00f3wki w tytule lub \u017ceby doda\u0107 dodatkowe zmiany w plikach.<\/p>\n\n\n\n<p>Polecenie\u00a0<em>git rebase -i<\/em>\u00a0to tzw. interaktywny rebase. Git uruchamia edytor, w kt\u00f3rym u\u017cytkownik mo\u017ce okre\u015bli\u0107 jakie kroki chce wykona\u0107 z poszczeg\u00f3lnym commitem. Pozwala m.in. z\u0142\u0105czy\u0107 commity, zmieni\u0107 nazw\u0119 commita, pomin\u0105\u0107 commit.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Odzyskanie usuni\u0119tego lokalnie commita<\/h4>\n\n\n\n<p>Eksperymentuj\u0105c z&nbsp;<em>git commit \u2013amend<\/em>&nbsp;lub&nbsp;<em>git reset \u2013hard<\/em>&nbsp;zdarza si\u0119, \u017ce naniesiona poprawka jeszcze pogarsza sytuacj\u0119.<\/p>\n\n\n\n<p>Przyk\u0142adowo, u\u017cywaj\u0105c polecenia<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ngit reset --hard HEAD~1\n<\/pre><\/div>\n\n\n<p>usuni\u0119to commit, kt\u00f3ry jednak mia\u0142 w sobie cz\u0119\u015b\u0107 istotnych tre\u015bci.<\/p>\n\n\n\n<p>Ze wzgl\u0119du na to, \u017ce branch jest tylko wska\u017anikiem, mo\u017cna go ponownie ustawi\u0107 na 'usuni\u0119tym\u2019 commitcie.<\/p>\n\n\n\n<p>Do poznania historii zmian brancha HEAD, s\u0142u\u017cy komenda&nbsp;<em>git reflog<\/em><\/p>\n\n\n\n<p>Przyk\u0142ad wyniku\u00a0<em>git reflog<\/em>\u00a0zaraz po 'git reset \u2013hard HEAD~1\u2032<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">d31ab44 HEAD@{0}: reset: moving to HEAD~1\n15e423a HEAD@{1}: checkout: moving from 2634d9211302b62056898f9856ff18e196a8b038 to master\n2634d92 HEAD@{2}: checkout: moving from 3b13d1bed0296e044fed99cd872f44c5c10ec826 to HEAD~1\n3b13d1b HEAD@{3}: checkout: moving from master to origin\/master\n15e423a HEAD@{4}: checkout: moving from 3b13d1bed0296e044fed99cd872f44c5c10ec826 to master\n3b13d1b HEAD@{5}: checkout: moving from master to origin\/master<\/pre>\n\n\n\n<p>Znaczniki HEAD@{0}, HEAD@{1} itd. s\u0105 to aliasy do commit\u00f3w, wypisanych w pierwszej kolumnie.<\/p>\n\n\n\n<p>Komentarz opisuje jaka komenda gita doprowadzi\u0142a do obecnego stanu.<\/p>\n\n\n\n<p>\u017beby branch master ponownie wskazywa\u0142 na commit z przed 'git reset \u2013hard\u2019, nale\u017cy przenie\u015b\u0107 go na etap HEAD@{1}. Np. komend\u0105&nbsp;<em>git reset \u2013hard HEAD@{1}<\/em>.<\/p>\n\n\n\n<p>W efekcie master b\u0119dzie ponownie wskazywa\u0142 'usuni\u0119ty\u2019 commit.<br>Do refloga zostanie dodany nowy wpis opisuj\u0105cy zmian\u0119:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n15e423a HEAD@{0}: reset: moving to HEAD@{1}\nd31ab44 HEAD@{1}: reset: moving to HEAD~1\n<\/pre><\/div>\n\n\n<p><strong>WA\u017bNE<\/strong><br>Baza danych gita opiera si\u0119 na zasadzie niezmiennych struktur, dlatego commity nie s\u0105 modyfikowane. Ze wzgl\u0119du na ograniczone zasoby dyskowe, cyklicznie (domy\u015blnie co 2 tygodnie) git, podczas synchronizacji repozytorium, uruchamia Garbage Colletor (<em>git gc<\/em>). Garbage Collector wyszukuje commity, kt\u00f3re nie s\u0105 oznaczone przez jakikolwiek branch\/tag i je usuwa.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Podsumowuj\u0105c<\/h3>\n\n\n\n<p>Git oferuje bardzo du\u017ce mo\u017cliwo\u015bci w organizowaniu repozytorium. Ze wzgl\u0119du na sw\u00f3j rozproszony charakter jest niezawodny. Organizacja bazy danych uniemo\u017cliwia usuwanie tre\u015bci, wi\u0119c nawet omy\u0142kowo usuni\u0119te dane, je\u017celi tylko by\u0142y scommitowane do gita, s\u0105 do odzyskania. Znajomo\u015b\u0107 metody poruszania si\u0119 po ga\u0142\u0119ziach i narz\u0119dzi do ich organizacji niew\u0105tpliwie u\u0142atwia codzienn\u0105 prac\u0119 z tym programem.<\/p>\n\n\n\n<p>Dla os\u00f3b bardziej dociekliwych polecam&nbsp;<a href=\"https:\/\/git-scm.com\/doc\" rel=\"nofollow\" >dokumentacj\u0119<\/a>&nbsp;gdzie opisane s\u0105 wszystkie zagadnienia zwi\u0105zane z budow\u0105 bazy danych i szczeg\u00f3\u0142owy opis komend.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;3589&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;6&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;4.3&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;4.3\\\/5 ( votes: 6)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Wsp\u00f3\u0142pracowa\u0107 z gitem&quot;,&quot;width&quot;:&quot;119.2&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 119.2px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            4.3\/5 ( votes: 6)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Git jest systemem kontroli wersji. Zapisuje historie zmian w \u015bledzonym katalogu.W kilku etapach postaram si\u0119 przybli\u017cy\u0107 jak wygl\u0105da praca z &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/wspolpracowac-z-gitem\/\">Continued<\/a><\/p>\n","protected":false},"author":34,"featured_media":3828,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":10,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[452,454,455,453],"class_list":["post-3589","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-git","tag-merge","tag-rebase","tag-scm"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2017\/01\/gittt.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/3589"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=3589"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/3589\/revisions"}],"predecessor-version":[{"id":19139,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/3589\/revisions\/19139"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/3828"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=3589"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=3589"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=3589"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}