Merge, update, and pull Git branches without using checkouts
Pracuję nad projektem, który ma 2 gałęzie, A I B. zazwyczaj pracuję nad gałęzią a i scalam rzeczy z gałęzi B. do scalania zazwyczaj wykonuję:
git merge origin/branchB
Jednakże, chciałbym również zachować lokalną kopię gałęzi B, ponieważ od czasu do czasu mogę sprawdzić gałąź bez uprzedniego połączenia z moją gałęzią A. w tym celu zrobiłbym:
git checkout branchB
git pull
git checkout branchA
Czy istnieje sposób na wykonanie powyższego w jednym poleceniu, bez konieczności przełączania gałęzi tam i z powrotem? Czy powinienem używać git update-ref
do tego? Jak?
10 answers
Krótka Odpowiedź
Tak długo, jak robisz fast-forward merge, możesz po prostu użyć
git fetch <remote> <sourceBranch>:<destinationBranch>
Przykłady:
# Merge local branch foo into local branch master,
# without having to checkout master first.
# Here `.` means to use the local repository as the "remote":
git fetch . foo:master
# Merge remote branch origin/foo into local branch foo,
# without having to checkout foo first:
git fetch origin foo:foo
Podczas gdy odpowiedź Amber będzie również działać w przypadkach szybkiego przewijania do przodu, użycie git fetch
w ten sposób jest nieco bezpieczniejsze niż tylko wymuszone przesuwanie referencji gałęzi, ponieważ git fetch
automatycznie zapobiegnie przypadkowym nie szybkim przewijaniu do przodu, o ile nie użyjesz +
w refspec.
Długa Odpowiedź
Ty nie można scalić gałęzi B z gałęzią a bez sprawdzenia A, jeśli spowoduje to scalenie bez szybkiego przewijania do przodu. Dzieje się tak dlatego, że kopia robocza jest potrzebna do rozwiązania ewentualnych konfliktów.
Jednakże, w przypadku fast-forward merges, jest to możliwe, ponieważ takie merges nigdy nie może prowadzić do konfliktów, z definicji. Aby to zrobić bez sprawdzania gałęzi, możesz użyć {[7] } z refspec.Oto przykład aktualizacji master
(wyłączenie zmiany bez przewijania do przodu) jeśli masz inną gałąź feature
sprawdzone:
git fetch upstream master:master
Ten przypadek użycia jest tak powszechny, że prawdopodobnie będziesz chciał utworzyć dla niego alias w swoim pliku konfiguracyjnym git, jak ten:
[alias]
sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'
To, co robi ten alias, jest następujące:
git checkout HEAD
: to sprawia, że kopia robocza jest odłączona od głowy. Jest to przydatne, jeśli chcesz zaktualizowaćmaster
, gdy akurat masz ją sprawdzoną. Myślę, że było to konieczne, ponieważ w przeciwnym razie odniesienie do gałęzimaster
nie ruszy się, ale nie pamiętam, czy to naprawdę jest z głowy.git fetch upstream master:master
: to szybko przenosi Twój lokalnymaster
w to samo miejsce coupstream/master
.git checkout -
sprawdza twoją poprzednio sprawdzoną gałąź (tak robi-
w tym przypadku).
Składnia git fetch
for (non-)fast-forward merges
Jeśli chcesz, aby polecenie fetch
nie powiodło się, jeśli aktualizacja jest nie-przewijanie do przodu, wtedy po prostu używasz refspec formularza
git fetch <remote> <remoteBranch>:<localBranch>
Jeśli chcesz zezwolić na aktualizacje bez przewijania do przodu, dodaj +
z przodu refspec:
git fetch <remote> +<remoteBranch>:<localBranch>
Zauważ, że możesz przekazać swoje lokalne repo jako parametr "zdalny" używając .
:
git fetch . <sourceBranch>:<destinationBranch>
Dokumentacja
Z git fetch
dokumentacja wyjaśniająca tę składnię (podkreślenie mine):
<refspec>
Format parametru
<refspec>
jest opcjonalny plus+
, po którym następuje źródłowy ref<src>
, po którym następuje dwukropek:
, po którym następuje docelowy ref<dst>
.zdalny ref pasujący
<src>
jest pobierany, a jeśli<dst>
nie jest pustym łańcuchem, lokalny ref pasujący do niego jest szybko przekazywany za pomocą<src>
. Jeśli zostanie użyty opcjonalny plus+
, lokalny ref jest aktualizowany nawet jeśli nie spowoduje to szybkiej aktualizacji.
Zobacz Też
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-17 01:13:59
Nie, Nie ma. Checkout docelowej gałęzi jest niezbędny, aby umożliwić Ci rozwiązywanie konfliktów, między innymi (jeśli Git nie jest w stanie automatycznie ich scalić).
Jednakże, jeśli połączenie jest szybkie, nie musisz sprawdzać gałęzi docelowej, ponieważ w rzeczywistości nie musisz niczego scalać - wystarczy zaktualizować gałąź, aby wskazywała na nowy ref head. Możesz to zrobić za pomocą git branch -f
:
git branch -f branch-b branch-a
Zaktualizuje branch-b
, aby wskazać głowę branch-a
.
Opcja -f
oznacza --force
, co oznacza, że musisz być ostrożny podczas jej używania. Nie używaj go, chyba że jesteś pewien, że połączenie będzie szybkie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-07 11:03:55
Jak powiedziała Amber, szybkie połączenia są jedynym przypadkiem, w którym można to zrobić. Każde inne scalenie musi przejść przez całą trójstronną scalanie, stosowanie łat, rozwiązywanie konfliktów - a to oznacza, że muszą być gdzieś pliki.
Przypadkiem mam skrypt, którego używam do tego: fast-forward merges bez dotykania drzewa roboczego (chyba że łączysz się z głową). Jest trochę długi, bo jest przynajmniej trochę wytrzymały - sprawdza się upewnij się, że merge będzie fast-forward, a następnie wykonuje je bez sprawdzania gałęzi, ale generuje te same wyniki, jak gdybyś miał - widzisz diff --stat
Podsumowanie zmian, a wpis w reflogu jest dokładnie jak fast forward merge, zamiast "reset", który otrzymujesz, jeśli używasz branch -f
. Jeśli nazwiesz ją git-merge-ff
i wrzucisz do katalogu bin, możesz wywołać ją jako polecenie git: git merge-ff
.
#!/bin/bash
_usage() {
echo "Usage: git merge-ff <branch> <committish-to-merge>" 1>&2
exit 1
}
_merge_ff() {
branch="$1"
commit="$2"
branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
if [ $? -ne 0 ]; then
echo "Error: unknown branch $branch" 1>&2
_usage
fi
commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
if [ $? -ne 0 ]; then
echo "Error: unknown revision $commit" 1>&2
_usage
fi
if [ "$(git symbolic-ref HEAD)" = "refs/heads/$branch" ]; then
git merge $quiet --ff-only "$commit"
else
if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
exit 1
fi
echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
if [ -z $quiet ]; then
echo "Fast forward"
git diff --stat "$branch@{1}" "$branch"
fi
else
echo "Error: fast forward using update-ref failed" 1>&2
fi
fi
}
while getopts "q" opt; do
case $opt in
q ) quiet="-q";;
* ) ;;
esac
done
shift $((OPTIND-1))
case $# in
2 ) _merge_ff "$1" "$2";;
* ) _usage
esac
P. S. Jeśli ktoś widzi jakieś problemy z tym skryptem, proszę o komentarz! To był napisz i zapomnij o pracy, ale chętnie ją poprawię.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-29 20:08:32
Można to zrobić tylko wtedy, gdy połączenie jest szybkie. Jeśli tak nie jest, to git musi sprawdzić pliki, aby móc je scalić!
To do it for a fast-forward only :
git fetch <branch that would be pulled for branchB>
git update-ref -m "merge <commit>: Fast forward" refs/heads/<branch> <commit>
Gdzie <commit>
jest pobranym commitem, do którego chcesz przewijać. Jest to w zasadzie jak użycie git branch -f
do przeniesienia gałęzi, z tą różnicą, że zapisuje ją również w reflogu tak, jakbyś faktycznie dokonał scalenia.
Proszę, proszę, proszę nie rób tego dla czegoś, co nie jest przewiń do przodu, albo po prostu zresetujesz swoją gałąź do innego commita. (Aby sprawdzić, sprawdź czy git merge-base <branch> <commit>
podaje SHA1 gałęzi.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-04 07:15:11
Innym, co prawda dość brutalnym sposobem jest po prostu odtworzenie gałęzi:
git fetch remote
git branch -f localbranch remote/remotebranch
To wyrzuca lokalną przestarzałą gałąź i ponownie tworzy tę o tej samej nazwie, więc używaj ostrożnie ...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-08 10:08:14
W Twoim przypadku możesz użyć
git fetch origin branchB:branchB
Który robi to, co chcesz (zakładając, że połączenie jest szybkie do przodu). Jeśli gałąź nie może zostać zaktualizowana, ponieważ wymaga połączenia bez przewijania do przodu, to nie powiedzie się to bezpiecznie z wiadomością.
Ta forma pobierania ma również kilka bardziej przydatnych opcji:
git fetch <remote> <sourceBranch>:<destinationBranch>
Zauważ, że <remote>
może być lokalnym repozytorium, a <sourceBranch>
może być gałęzią śledzącą. Możesz więc zaktualizować lokalny oddział, nawet jeśli nie jest sprawdzony, bez dostępu do sieć .
Obecnie mój dostęp do serwera upstream jest przez powolną sieć VPN, więc okresowo łączę się, git fetch
, aby zaktualizować wszystkie piloty, a następnie rozłączyć. Wtedy, jeśli, powiedzmy, zdalny Mistrz się zmienił, mogę zrobić
git fetch . remotes/origin/master:master
Aby bezpiecznie zaktualizować mojego lokalnego mistrza, nawet jeśli obecnie mam sprawdzoną inną gałąź. Nie jest wymagany dostęp do sieci.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-24 22:39:47
Możesz sklonować repo i połączyć w nowym repo. Na tym samym systemie plików, to będzie hardlink zamiast kopiować większość danych. Zakończ, wyciągając wyniki do oryginalnego repo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-11 18:00:02
Enter git-forward-merge :
Bez potrzeby kasowania miejsca docelowego,
git-forward-merge <source> <destination>
łączy źródło z docelową gałęzią.
Https://github.com/schuyler1d/git-forward-merge
Działa tylko dla automatycznych scaleń, jeśli występują konflikty, musisz użyć zwykłego scalania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-29 17:15:10
W wielu przypadkach (np. scalanie), możesz po prostu użyć zdalnej gałęzi bez konieczności aktualizacji lokalnej gałęzi śledzenia. Dodanie wiadomości w reflogu brzmi jak przesada i powstrzyma ją przed szybszym działaniem. Aby ułatwić odzyskiwanie danych, Dodaj do git config
[core]
logallrefupdates=true
Następnie wpisz
git reflog show mybranch
Aby zobaczyć najnowszą historię twojej gałęzi
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-25 22:19:35
Napisałem funkcję powłoki dla podobnego przypadku użycia, z którym spotykam się codziennie w projektach. Jest to w zasadzie skrót do utrzymywania lokalnych oddziałów na bieżąco ze wspólnym oddziałem, takim jak develop przed otwarciem PR itp.
Publikowanie tego, nawet jeśli nie chcesz używać
checkout
, na wypadek, gdyby inni nie mieli nic przeciwko temu ograniczeniu.
glmh
("git pull and merge here") będzie automatycznie checkout branchB
, pull
najnowsze, re-checkout branchA
i merge branchB
.
Nie odnosi się do trzeba zachować lokalną kopię branchA, ale można go łatwo zmodyfikować, aby to zrobić, dodając krok przed sprawdzeniem branchB. Coś w tym stylu...
git branch ${branchA}-no-branchB ${branchA}
W przypadku prostych fast-forward Scala, przeskakuje to do komunikatu commit.
W przypadku fuzji non fast-forward, to umieszcza Twoją gałąź w stanie rozwiązywania konfliktów (prawdopodobnie będziesz musiał interweniować).
Aby ustawić, Dodaj do .bashrc
lub .zshrc
, itd:
glmh() {
branchB=$1
[ $# -eq 0 ] && { branchB="develop" }
branchA="$(git branch | grep '*' | sed 's/* //g')"
git checkout ${branchB} && git pull
git checkout ${branchA} && git merge ${branchB}
}
Użycie:
# No argument given, will assume "develop"
> glmh
# Pass an argument to pull and merge a specific branch
> glmh your-other-branch
Uwaga: Jest to nie wystarczająco wytrzymałe, aby przekazać args poza nazwą gałęzi
git merge
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 00:03:02