Używam Perforce od wielu lat. Chciałbym przełączyć się na używanie git do mojego osobistego kodu, ale wszystkie samouczki git, które widziałem, zakładają, że masz pełną kontrolę źródła n00b (co czyni je niesamowicie żmudnymi) lub że jesteś do tego przyzwyczajony svn (którym nie jestem).
Znam p4 i rozumiem też ideę rozproszonego systemu kontroli źródła (więc nie potrzebuję promocji, dzięki). To, co chciałbym, to tablica translacji z polecenia p4 na równoważne polecenia git, a także polecenia „nie można żyć bez”, które nie mają odpowiednika p4.
Ponieważ podejrzewam, że każdy użytkownik p4 używa innego podzbioru p4, oto kilka rzeczy, które regularnie robię w p4, które chciałbym robić w git, a które nie są od razu widoczne w dokumentach, które przeglądałem :
- utwórz wiele oczekujących list zmian w jednym kliencie. (
p4 change
) - edytuj oczekującą listę zmian. (też
p4 change
) - zobacz listę wszystkich moich oczekujących list zmian (
p4 changes -s pending
) - lista wszystkich zmienionych plików w moim kliencie (
p4 opened
) lub w oczekującej liście zmian (p4 describe
) - zobacz różnicę oczekującej listy zmian (używam do tego skryptu opakowującego, który używa
p4 diff
ip4 describe
) - dla danego pliku, zobacz, które przesłane listy zmian wpłynęły na które linie (
p4 annotate
) - dla danego pliku zobacz listę opisów list zmian, które wpłynęły na plik (
p4 log
) - prześlij oczekującą listę zmian (
p4 submit -c
) - przerwać oczekującą listę zmian (
p4 revert
)
Wiele z nich obraca się wokół „list zmian”. „lista zmian” to terminologia p4. Jaki jest odpowiednik terminu git?
Wygląda na to, że użytkownicy git mogą używać gałęzi zamiast tego, co p4 nazywa listami zmian. Nieco zagmatwane, ponieważ p4 ma również coś, co nazywa się gałęzią, chociaż wydają się być tylko niejasno powiązanymi pojęciami. (Chociaż zawsze myślałem, że koncepcja gałęzi p4 jest dość dziwna, po raz kolejny różni się od klasycznej koncepcji gałęzi RCS).
W każdym razie ... Nie jestem pewien, jak osiągnąć to, co normalnie robię na listach zmian p4 z gałęziami git. W p4 mogę zrobić coś takiego:
$ p4 edit a.txt
$ p4 change a.txt
Change 12345 created.
W tym momencie mam listę zmian, która zawiera plik.txt. Mogę edytować opis i kontynuować pracę bez przesyłania listy zmian. Ponadto, jeśli okaże się, że muszę wprowadzić pewne zmiany w innych plikach, na przykład naprawić błąd w innej warstwie kodu, mogę to zrobić w tym samym kliencie:
$ p4 edit z.txt
$ p4 change z.txt
Change 12346 created.
Teraz mam dwie oddzielne listy zmian w tym samym kliencie. Mogę pracować nad nimi jednocześnie i nie muszę nic robić, aby „przełączać się” między nimi. Kiedy przychodzi czas na zatwierdzenie, mogę przesłać je osobno:
$ p4 submit -c 12346 # this will submit the changes to z.txt
$ p4 submit -c 12345 # this will submit the changes to a.txt
Nie mogę wymyślić, jak to powtórzyć w git. Z moich eksperymentów wynika, że nie git add
jest to związane z bieżącą gałęzią. O ile wiem, kiedy git commit
zamierzam zatwierdzić wszystkie pliki, które wykonałem, git add
bez względu na gałąź, w której byłem w tym czasie:
$ git init
Initialized empty Git repository in /home/laurence/git-playground/.git/
$ ls
a.txt w.txt z.txt
$ git add -A .
$ git commit
Initial commit.
3 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 a.txt
create mode 100644 w.txt
create mode 100644 z.txt
$ vi a.txt z.txt
2 files to edit
$ git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: a.txt
# modified: z.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git branch aardvark
$ git checkout aardvark
M a.txt
M z.txt
Switched to branch 'aardvark'
$ git add a.txt
$ git checkout master
M a.txt
M z.txt
Switched to branch 'master'
$ git branch zebra
$ git checkout zebra
M a.txt
M z.txt
Switched to branch 'zebra'
$ git add z.txt
$ git status
# On branch zebra
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a.txt
# modified: z.txt
#
$ git checkout aardvark
M a.txt
M z.txt
Switched to branch 'aardvark'
$ git status
# On branch aardvark
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: a.txt
# modified: z.txt
W tym przykładzie gałęzie mrównika i zebry wydają się zawierać dokładnie ten sam zestaw zmian, a na podstawie ich wyniku git status
wydaje się, że wykonanie zatwierdzenia w jednej z nich będzie miało ten sam efekt. czy robię coś źle?
Odpowiedzi:
Nie używałem zbyt często siły, więc może to nie być dokładnie tłumaczenie 1: 1. Z drugiej strony, rozproszone systemy kontroli źródła, takie jak git i mercurial, i tak mają inny przepływ pracy, więc tak naprawdę nie ma (i nie powinno być) tłumaczenia 1: 1. Tak czy inaczej, oto idzie:
Utwórz wiele oczekujących list zmian -> Zamiast tego użyj gałęzi. W git branch jest lekki i szybki, jego utworzenie zajmuje mniej niż sekundę, a łączenie zajmuje zwykle mniej niż dwie sekundy. Nie bój się często rozgałęziania i rebase.
Lub zrób to wszystko w jednej linii:
Zobacz listę wszystkich oczekujących list zmian -> Ponieważ odpowiednikiem wielu oczekujących list zmian jest wiele gałęzi, wystarczy wyświetlić gałęzie:
Jeśli chcesz zobaczyć również zdalne oddziały:
Za dobrą praktykę uważa się natychmiastowe usuwanie gałęzi po pomyślnym scaleniu, aby nie trzeba było śledzić, która gałąź oczekuje na scalenie, a która już została scalona.
Lista wszystkich zmienionych plików -> Dla pojedynczej oczekującej "listy zmian" w określonej gałęzi git ma pojęcie indeksu lub pamięci podręcznej. Aby zatwierdzić zmianę, musisz najpierw dodać pliki do tego indeksu. Pozwala to ręcznie wybrać, która grupa plików reprezentuje pojedynczą zmianę, lub zignorować nieistotne pliki. Aby zobaczyć stan, które pliki są dodawane lub nie do tego indeksu, po prostu wykonaj:
Zobacz różnicę oczekującej listy zmian -> Są to dwie części. Najpierw zobacz różnicę między katalogiem roboczym a indeksem:
Ale jeśli chcesz poznać różnicę między tym, co teraz wpisujesz, a ostatnim zatwierdzeniem, to naprawdę prosisz o różnicę między katalogiem roboczym + indeksem a nagłówkiem:
Dla danego pliku zobacz, które przesłane listy zmian wpłynęły na które wiersze -> To proste:
lub nawet lepiej, jeśli jesteś w środowisku okienkowym:
Git gui zajmuje więcej czasu na parsowanie pliku (został napisany w tcl zamiast w C), ale ma wiele fajnych funkcji, w tym możliwość „podróży w czasie” z powrotem do przeszłości poprzez kliknięcie na identyfikator zatwierdzenia. Chciałbym tylko, żeby zaimplementowali funkcję „podróży w czasie” do przyszłości, abym mógł dowiedzieć się, jak dany błąd zostanie ostatecznie rozwiązany ;-)
Dla danego pliku zobacz listę opisów list zmian, które wpłynęły na plik -> również łatwe:
Ale git log jest znacznie potężniejszym narzędziem niż tylko to. W rzeczywistości większość moich osobistych skryptów jest pobierana z dziennika gita, aby odczytać repozytorium. Przeczytaj stronę podręcznika.
Prześlij oczekującą listę zmian -> Również łatwe:
Zobacz moją odpowiedź na poprzednie pytanie, aby zobaczyć mój typowy przepływ pracy w gicie: Nauka Git. Muszę wiedzieć, czy jestem na dobrej drodze
Jeśli zastosujesz się do opisanego przeze mnie przepływu pracy, zauważysz, że narzędzia takie jak gitk są znacznie bardziej wartościowe, ponieważ pozwalają wyraźnie zobaczyć grupy zmian.
Dodatkowa odpowiedź:
Git jest bardzo elastyczny i istnieje kilka sposobów na zrobienie tego, co opisujesz. Należy pamiętać, aby zawsze rozpoczynać nową gałąź dla każdej funkcji, nad którą pracujesz. Oznacza to, że gałąź główna nie jest dotykana, więc zawsze możesz do niej wrócić, aby naprawić błędy. Pracę w git prawie zawsze należy zacząć od:
Teraz możesz edytować plik a.txt. Aby pracować jednocześnie nad inną funkcją, wykonaj:
Teraz możesz edytować plik z.txt. Aby wrócić do a.txt:
Ale poczekaj, są zmiany w nowej funkcji-z, a git nie pozwoli ci zmienić gałęzi. W tym momencie masz dwie możliwości. Pierwsza jest najprostsza, zatwierdź wszystkie zmiany w bieżącej gałęzi:
To właśnie polecam. Ale jeśli naprawdę nie jesteś gotowy, aby zatwierdzić kod, możesz go tymczasowo ukryć:
Teraz możesz przełączyć się na gałąź new-feature-a. Aby wrócić do kodu, nad którym pracowałeś, po prostu włóż skrytkę:
Kiedy wszystko jest gotowe, z powrotem scal wszystkie zmiany do mastera:
Ponieważ scalanie jest tak szybkie i łatwe (łatwe, ponieważ konflikty są tak rzadkie, a rozwiązywanie konfliktów, kiedy się zdarzają, niezbyt trudne), używamy gałęzi w git do wszystkiego.
Oto kolejny przykład typowego użycia gałęzi w git, którego nie widzisz w innych narzędziach kontroli źródła (z wyjątkiem być może mercurial):
Chcesz ciągle zmieniać pliki konfiguracyjne, aby odzwierciedlić środowisko programistyczne? Następnie użyj gałęzi:
Teraz edytuj pliki konfiguracyjne w ulubionym edytorze, a następnie zatwierdź zmiany:
Teraz każda nowa gałąź może zaczynać się od gałęzi dev-config zamiast master:
Gdy skończysz, usuń zmiany w dev-config z nowej gałęzi funkcji za pomocą interaktywnej rebase:
Usuń niepotrzebne zmiany, a następnie zapisz. Teraz masz czystą gałąź bez niestandardowych edycji konfiguracji. Czas na powrót do mastera:
Należy zauważyć, że usuwanie zmian za pomocą
git rebase -i
nawet działa, gdy wszystkie zmiany zachodzą w tym samym pliku. Git pamięta zmiany, a nie zawartość plików *.* uwaga: właściwie, technicznie nie do końca prawda, ale jako użytkownik tak się czuje
Więcej dodatkowej odpowiedzi:
Z twoich komentarzy wynika, że chcesz mieć dwie gałęzie, aby istniały jednocześnie, abyś mógł przetestować, jak działa połączony kod. Cóż, to dobry sposób, aby zilustrować siłę i elastyczność gałęzi.
Najpierw kilka słów na temat wpływu taniego rozgałęziania i modyfikowalnej historii na przepływ pracy. Kiedy używałem CVS i SVN, zawsze byłem trochę niechętny do zatwierdzania. Dzieje się tak, ponieważ zatwierdzenie niestabilnego kodu nieuchronnie zniszczyłoby działający kod innych osób. Ale z git straciłem ten strach. To dlatego, że w git inni ludzie nie otrzymają moich zmian, dopóki nie połączę ich z master. Więc teraz zaczynam pisać kod co 5 linii, które piszę. Nie potrzebujesz doskonałej przewidywania, aby się zaangażować. Musisz tylko zmienić swój sposób myślenia: commit-to-branch == add-to-changeset, merge-to-master == commit-changeset.
Wróćmy więc do przykładów. Oto jak bym to zrobił. Powiedzmy, że masz gałąź
new-feature-z
i chcesz ją przetestowaćnew-feature-a
. Po prostu utworzyłbym nową gałąź, aby ją przetestować:Teraz możesz przetestować. Jeśli chcesz coś zmodyfikować, aby funkcja feature-z działała z feature-a, zrób to. Jeśli tak, możesz z powrotem scalić zmiany w odpowiedniej gałęzi. Służy
git rebase -i
do usuwania nieistotnych zmian z scalania.Alternatywnie możesz również użyć git rebase, aby tymczasowo zmienić podstawę new-feature-z, aby wskazywała na new-feature-a:
Teraz historia rozgałęzień jest modyfikowana tak, że new-feature-z będzie bazował na new-feature-a zamiast master. Teraz możesz przetestować. Wszelkie zmiany dokonane w tej gałęzi będą należeć do gałęzi new-feature-z. Jeśli chcesz zmodyfikować nową funkcję, po prostu przełącz się z powrotem do niej i rebase, aby uzyskać nowe zmiany:
Kiedy skończysz, po prostu wróć do mastera, aby usunąć zmiany z nowej funkcji:
Nie bój się otwierać nowego oddziału. Nie bój się założyć jednorazowej gałęzi. Nie bój się wyrzucić gałęzi. A ponieważ merge == submit and commit == add-to-changeset, nie bój się często zatwierdzać. Pamiętaj, commit to najlepsze narzędzie programisty do cofania zmian.
Aha, i jeszcze jedno, w git usunięte gałęzie nadal istnieją w twoim repozytorium. Więc jeśli przypadkowo usunąłeś coś, co później okaże się przydatne, zawsze możesz to odzyskać, przeszukując historię. Nie bój się więc wyrzucać gałęzi.
źródło
Nie mam wystarczającego doświadczenia z p4, aby stworzyć rzeczywisty arkusz do ściągnięcia, ale są przynajmniej pewne podobieństwa, na których można się oprzeć. "Zbiór zmian" p4 to "zatwierdzenie" gita.
Zmiany w lokalnej przestrzeni roboczej są dodawane do „indeksu” za pomocą
git add
, a indeks zostaje później zatwierdzonygit commit
. Więc indeks jest twoją oczekującą listą zmian, dla wszystkich zamiarów i celów.Patrzysz na zmiany za pomocą
git diff
igit status
, gdziegit diff
zwykle pokazuje zmiany między obszarem roboczym a indeksem, alegit diff --cached
pokazuje zmiany między indeksem a repozytorium (= twoja oczekująca lista zmian).Aby uzyskać bardziej szczegółowe informacje, polecam http://progit.org/book/ . Ponieważ ogólnie znasz kontrolę wersji, prawdopodobnie możesz ją przejrzeć i wyodrębnić informacje specyficzne dla gita ...
źródło
Podobnie jak ty cierpię z powodu braku koncepcji „listy zmian”, która nie jest dokładnie tym samym, co git branches.
Napisałbym mały skrypt, który utworzy plik listy zmian z listą plików na tej liście zmian.
Kolejne polecenie, aby przesłać tylko określoną listę zmian, po prostu wywołując git commit -a @ change_list_contents.txt, a następnie „git commit”
Mam nadzieję, że to pomoże, Elias
źródło
W git jest lżejsza alternatywa, która może stanowić część twojego przepływu pracy; używając obszaru przemieszczania git.
Często po prostu wprowadzam zmiany, a następnie przesyłam je jako kilka zatwierdzeń (np. Dodam instrukcje debugowania, refaktoryzację, faktycznie naprawiam błąd). Zamiast konfigurować listy zmian, a następnie wprowadzić zmiany, a następnie przesłać, możesz po prostu wprowadzić zmiany, a następnie wybrać sposób ich przesłania (opcjonalnie korzystając z obszaru przejściowego git).
Możesz zatwierdzić określone pliki z wiersza poleceń za pomocą:
Lub jawnie najpierw przemieszczaj pliki:
git gui pozwoli ci wybrać linie lub porcje z plików, aby zbudować zatwierdzenie w obszarze przejściowym. Jest to bardzo przydatne, jeśli masz zmiany w jednym pliku, które chcesz umieścić w różnych zatwierdzeniach. Przeszedłem od gita do konieczności i jest to jedna rzecz, za którą naprawdę tęsknię.
W przypadku tego przepływu pracy należy pamiętać o małym zastrzeżeniu. Jeśli dokonasz zmian A i B w pliku, przetestuj plik, a następnie zatwierdź A, a wtedy nie przetestowałeś tego zatwierdzenia (niezależnie od B).
źródło
To nie odpowiada konkretnie na twoje pytanie, ale nie wiem, czy wiesz, że wersję forfororce dla 2 użytkowników i 5 obszarów roboczych można pobrać i używać za darmo ze strony internetowej perforce .
W ten sposób, jeśli chcesz, możesz używać siły w domu do swoich osobistych projektów. Jedyną irytacją jest 5 obszarów roboczych, które mogą być nieco ograniczające, ale niewiarygodne jest mieć siłę dostępną do użytku domowego.
źródło
Po dość intensywnym używaniu zarówno Perforce, jak i git, jest tylko jeden sposób, aby znaleźć się w pobliżu list zmian Perforce z git.
Pierwszą rzeczą do zrozumienia jest to, że poprawne zaimplementowanie tej funkcjonalności w git w taki sposób, że nie jest to kompletna kluga, np. Próba wbicia jej w gałęzie, wymagałoby następującej zmiany: git wymagałby wielu obszarów przejściowych dla jednej gałęzi .
Listy zmian Perforce pozwalają na przepływ pracy, który po prostu nie ma odpowiednika w git. Rozważ następujący przepływ pracy:
Jeśli spróbujesz to zrobić za pomocą gałęzi w git, skończysz z dwoma gałęziami, z których jedna zawiera zmiany w pliku
A
, a druga ma zmiany w plikuB
, ale nie ma miejsca, w którym możesz zobaczyć zmiany w obu plikachA
iB
w o tym samym czasie.Najbliższym przybliżeniem widzę jest wykorzystanie
git add . -p
, a następnie użyj'a'
i'd'
sub-polecenia, aby wybrać lub odrzucić całe pliki. Jednak to nie jest dokładnie to samo, a różnica tutaj wynika z fundamentalnej rozbieżności w ogólnym sposobie działania obu systemów.Git (i subversion, nie ma to znaczenia w tej dyskusji) pozwalają na zmianę pliku bez uprzedniego powiadamiania nikogo o tym. Po prostu zmieniasz plik, a następnie pozwalasz gitowi to wszystko uporządkować po zatwierdzeniu zmian. Perforce wymaga, abyś aktywnie pobierał plik, zanim zmiany zostaną dopuszczone, iz tego powodu listy zmian muszą istnieć. Zasadniczo Perforce wymaga dodania pliku do indeksu przed jego zmianą. Stąd potrzeba wielu list zmian w Perforce, a także powód, dla którego git nie ma odpowiednika. Po prostu ich nie potrzebuje.
źródło
Z Git 2.27 (Q2 2020) "
git p4
" nauczyłem się czterech nowych podpięć, a także "--no-verify
" opcji ich ominięcia (i istniejącego "p4-pre-submit
" podpięcia).Zobacz commit 1ec4a0a , commit 38ecf75 , commit cd1e0dc (14 lutego 2020) i commit 4935c45 , commit aa8b766 , commit 9f59ca4 , commit 6b602a2 (11 lutego 2020) autorstwa Ben Keene (
seraphire
) .(Scalone przez Junio C Hamano -
gitster
- w zatwierdzeniu 5f2ec21 , 22 kwietnia 2020)Przed Git 2.28 (Q3 2020)
--prepare-p4-only
opcja „ ” miała się zatrzymać po powtórzeniu jednego zestawu zmian, ale działała dalej (przez pomyłkę?)Zobacz commit 2dfdd70 (12 maja 2020) autorstwa Ben Keene (
seraphire
) .(Scalone przez Junio C Hamano -
gitster
- w zatwierdzeniu 7a8fec9 , 02 czerwca 2020)źródło