Korzystanie z programu Git (index)
Podczas pracy z Gitem może pojawić się sytuacja, kiedy jeden plik w różnych wersjach jest poddany różnym modyfikacjom. Wtedy operacja łączenia wersji prowadzi do konfliktu. Konflikty można edytować ręcznie w plikach lub użyć wybranego narzędzia do obsługi konfliktu. Polecane narzędzia open source:
Pliki z konfliktami są specjalnie zaznaczane w indeksie, dlatego "git commit" nie uda się zrobić, a "git status" raportuje "unmerged files".
Zakładam, że istnieją dwie gałęzie: master i testing.
$ git checkout master $ git merge testing # Pojawia się konflikt w pliku a1.txt. # Przykładowy komunikat: Auto-merging a1.txt CONFLICT (content): Merge conflict in a1.txt Automatic merge failed; fix conflicts and then commit the result. $ git status # On branch master # Unmerged paths: # (use "git add/rm <file>..." as appropriate to mark resolution) # # both modified: a1.txt # no changes added to commit (use "git add" and/or "git commit -a") $ cat a1.txt # oglądamy miejsce konfliktu plik a1 <<<<<<< HEAD zmiana a1 w galezi master ======= zmiana a1 w galezi testing >>>>>>> testing # Wywołanie konkretnego narzędzia do łączenia. # git mergetool -t meld # git mergetool --tool=meld $ git mergetool merge tool candidates: meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis bc3 emerge vimdiff Merging: a1.txt Normal merge conflict for 'a1.txt': {local}: modified file {remote}: modified file Hit return to start merge resolution tool (gvimdiff): # Po zainstalowaniu KDiff3 i Meld domyślnie uruchamia się Meld. # Po wykonaniu edycji a1.txt jest zmieniony, a poprzednia wersja # jest zapisana w pliku a1.txt.orig. # Czasem jest pytanie od Gita, czy konflikt jest rozwiązany # (Git nie pyta, kiedy skorzystał z exit code). $ git status # sprawdzamy stan repo # On branch master # Changes to be committed: # # modified: a1.txt # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # a1.txt.orig $ rm a1.txt.orig # usuwam wersję z zaznaczonymi konfliktami $ git add -A $ git commit -m "Merge branch testing."
Zakładam, że lokalna gałąź master śledzi gałąź origin/master.
# Repo zdalne to mgr-tmp. # W repo1 i repo2 jest plik a1, jest synchronizacja. # W repo2 tworzę plik b1 i robię git push. # W repo1 tworzę plik a2 i git push się nie udaje (non-fast-forward): $ git push Password for 'https://ufkapano@bitbucket.org': To https://ufkapano@bitbucket.org/ufkapano/mgr-tmp.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'https://ufkapano@bitbucket.org/ufkapano/mgr-tmp.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Merge the remote changes (e.g. 'git pull') hint: before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. # W repo1 robię git pull, udaje się, historia jest nieliniowa. # Nowa rewizja to "Merge branch 'master' of mgr-tmp". # W repo1 robię git push. # W repo2 robię git pull, jest synchronizacja.
# W repo2 zmieniam a2 i robię git commit, git push. # W repo1 zmieniam a2, robię git commit. git push się nie udaje. # W repo1 robię git fetch. # Uaktualnia się origin/master. Próbuje git rebase. $ git rebase origin/master First, rewinding head to replay your work on top of it... Applying: a2 changed on dell. Using index info to reconstruct a base tree... Falling back to patching base and 3-way merge... Auto-merging tests/a2.txt CONFLICT (content): Merge conflict in tests/a2.txt Failed to merge in the changes. Patch failed at 0001 a2 changed on dell. When you have resolved this problem run "git rebase --continue". If you would prefer to skip this patch, instead run "git rebase --skip". To check out the original branch and stop rebasing run "git rebase --abort". # Zmiana z repo2 jest nałożona. # W pliku a2 jest zaznaczony konflikt. # Zmieniam ręcznie rewizję zrobioną w repo1. # Ta stara rewizja z repo1 nie będzie widziana w historii! $ git add -A $ git rebase --continue $ git push
# W repo2 zmieniam a2 i robię git commit, git push. # W repo1 zmieniam a2, robię git commit. git push się nie udaje. # W repo1 robię git fetch. # Uaktualnia się origin/master. Próbuje git merge. $ git merge origin/master Auto-merging tests/a2.txt CONFLICT (content): Merge conflict in tests/a2.txt Automatic merge failed; fix conflicts and then commit the result. # Konflikt rozwiązuje ręcznie. $ git add -A $ git commit -m "Merge branch origin/master." $ git push