Jak znaleźć najbliższego rodzica oddziału Git?

419

Załóżmy, że mam następujące lokalne repozytorium z drzewem zatwierdzeń, takim jak to:

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

masterjest mój, to jest najnowszy stabilny kod wydania , developjest mój, to jest „następny” kod wydania i featurejest to nowa funkcja w przygotowaniudevelop .

To, co chcę robić na moim zdalnym repozytorium za pomocą haków, polega na featureodmowie wypchnięcia, chyba że zatwierdzenie fjest bezpośrednim potomkiem developHEAD. tzn. drzewo zatwierdzeń wygląda tak, ponieważ funkcja jest git rebasewłączona d.

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

Czy możliwe jest:

  • Zidentyfikować nadrzędną gałąź feature?
  • Zidentyfikuj zatwierdzenie w gałęzi nadrzędnej, która fjest potomkiem?

Stamtąd sprawdziłbym, czym jest HEAD gałęzi nadrzędnej, i sprawdzić, czy fpoprzednik pasuje do HEAD gałęzi nadrzędnej, aby ustalić, czy funkcja wymaga ponownego bazowania.

Peter Farmer
źródło
to pytanie należy przeformułować, aby znaleźć rodzica rodzica.
Tim Boland

Odpowiedzi:

347

Zakładając, że zdalne repozytorium posiada kopię rozwinięcia gałęzi (początkowy opis opisuje go w lokalnym repozytorium, ale to brzmi jak również istnieje w pilocie), powinieneś być w stanie osiągnąć to, co myślę, że chcesz, ale podejście różni się nieco od tego, co sobie wyobrażałeś.

Historia Git opiera się na DAG zatwierdzeń. Gałęzie (i ogólnie „referencje”) są tylko przejściowymi etykietami, które wskazują na określone zatwierdzenia w stale rosnącym DAG zatwierdzania. W związku z tym relacje między oddziałami mogą się zmieniać w czasie, ale związek między zatwierdzeniami się nie zmienia.

    ---o---1                foo
            \
             2---3---o      bar
                  \
                   4
                    \
                     5---6  baz

Wygląda na to, że bazjest oparty na (starej wersji) bar? Ale co jeśli usuniemy bar?

    ---o---1                foo
            \
             2---3
                  \
                   4
                    \
                     5---6  baz

Teraz wygląda na to, że bazjest oparty na foo. Ale pochodzenie bazsię nie zmieniło, po prostu usunęliśmy etykietę (i wynikające z tego zwisające zatwierdzenie). A jeśli dodamy nową etykietę w 4?

    ---o---1                foo
            \
             2---3
                  \
                   4        quux
                    \
                     5---6  baz

Teraz wygląda na to, że bazjest oparty na quux. Mimo to pochodzenie się nie zmieniło, zmieniły się tylko etykiety.

Gdybyśmy jednak pytali „czy popełnienie 6potomka popełnienia 3?” (zakładając 3i 6są to pełne nazwy zatwierdzeń SHA-1), wówczas odpowiedź brzmiałaby „tak”, niezależnie od tego, czy etykiety bari quuxsą obecne, czy nie.

Można więc zadawać pytania typu „czy wypychany zatwierdzenie jest potomkiem aktualnej końcówki gałęzi rozwijania ?”, Ale nie można rzetelnie zadać pytania „jaka jest gałąź nadrzędna zatwierdzonego przekazu?”.

Najbardziej wiarygodne pytanie, które wydaje się zbliżać do tego, czego chcesz, to:

Dla wszystkich przodków wypychanego zatwierdzenia (wyłączając bieżącą wskazówkę dewelopera i jej przodków), którzy mają bieżącą wskazówkę rozwijania jako rodzic:

  • czy istnieje przynajmniej jedno takie zatwierdzenie?
  • czy wszystkie takie zatwierdzenia zatwierdzają osoby samotnie wychowujące dzieci?

Które można zaimplementować jako:

pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_children_of_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
    ,)     echo "must descend from tip of '$basename'"
           exit 1 ;;
    ,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
           exit 1 ;;
    ,*)    exit 0 ;;
esac

To obejmie część tego, co chcesz ograniczyć, ale może nie wszystko.

Dla odniesienia, oto rozszerzona przykładowa historia:

    A                                   master
     \
      \                    o-----J
       \                  /       \
        \                | o---K---L
         \               |/
          C--------------D              develop
           \             |\
            F---G---H    | F'--G'--H'
                    |    |\
                    |    | o---o---o---N
                     \   \      \       \
                      \   \      o---o---P
                       \   \   
                        R---S

Powyższy kod można wykorzystać do odrzucenia Hi Sprzyjmując H', J, K, lub N, ale również zaakceptować Li P(obejmują one scala, ale nie połączyć końcówkę rozwijać ).

Aby odrzucić Li P, możesz zmienić pytanie i zadać

Dla wszystkich przodków wypchniętego zatwierdzenia (z wyjątkiem aktualnej końcówki develop i jego przodków):

  • czy są jakieś zobowiązania z dwojgiem rodziców?
  • jeśli nie, to czy przynajmniej jedno takie zatwierdzenie ma bieżącą wskazówkę dotyczącą rozwoju (jedynego) rodzica?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_commits_beyond_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
    *\ *)          echo "must not push merge commits (rebase instead)"
                   exit 1 ;;
    *"$baserev"*)  exit 0 ;;
    *)             echo "must descend from tip of '$basename'"
                   exit 1 ;;
esac
Chris Johnsen
źródło
Rozumiem: git: fatal: dwuznaczny argument „...”: zarówno wersja, jak i nazwa pliku. jaka jest intencja potrójnych kropek?
Jack Ukleja,
1
@ Schneider Jestem pewien, że „...” ma być symbolem zastępczym w tym przykładzie: jeśli zastąpisz go SHA zatwierdzenia, w którym próbujesz wykonać tę kontrolę (powiedzmy HEAD oddziału jesteś aktualnie włączony), wszystko działa dobrze.
Daniel Brady,
Dzięki za tę wyszukaną odpowiedź! To jest bardzo przydatne. Chcę zrobić podobny hak, ale nie chcę na stałe wpisywać nazwy gałęzi programistycznej. Czyli chcę haka do zapobiegania bazowaniu na gałęzi innej niż gałąź nadrzędna. Jeśli dobrze rozumiem twoją odpowiedź (jestem nowy w bash i tak dalej), to nie jest ujęte w twojej odpowiedzi, prawda? Czy jest na to sposób?
Kemeia,
Czy chcesz odpowiedzieć na powiązane pytanie? Nie udało mi się zmusić twojego kodu do pracy w repozytorium REMOTE. Oto link do pytania uzupełniającego na temat tego, jak dostosować swoje podejście do pracy z repozytorium REMOTE: stackoverflow.com/questions/49619492/...
CodeMed
Nie działało to dla mnie, gdy miałem develop > release > feature, wróciłem do rozwoju i wymaga to znajomości z rodzicem. Rozwiązaniem mojego problemu było stackoverflow.com/a/56673640/2366390
verdverm
240

Reefrasal

Innym sposobem sformułowania pytania jest „Jaki jest najbliższy zatwierdzenie rezydujące w gałęzi innej niż bieżąca gałąź i która to gałąź?”

Rozwiązanie

Możesz go znaleźć z odrobiną magii wiersza poleceń

git show-branch \
| sed "s/].*//" \
| grep "\*" \
| grep -v "$(git rev-parse --abbrev-ref HEAD)" \
| head -n1 \
| sed "s/^.*\[//" 

Z awk :

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

Oto jak to działa:

  1. Wyświetl historię tekstową wszystkich zatwierdzeń, w tym zdalnych oddziałów.
  2. Przodkowie bieżącego zatwierdzenia są oznaczeni gwiazdką. Odfiltruj wszystko inne.
  3. Zignoruj ​​wszystkie zatwierdzenia w bieżącej gałęzi.
  4. Pierwszym wynikiem będzie najbliższa gałąź przodka. Zignoruj ​​inne wyniki.
  5. Nazwy gałęzi są wyświetlane [w nawiasach]. Zignoruj ​​wszystko poza nawiasami i nawiasami.
  6. Czasami nazwa gałęzi będzie zawierać ~ # lub ^ #, aby wskazać, ile zatwierdzeń znajduje się między referencyjnym zatwierdzeniem a końcówką gałęzi. Nie obchodzi nas to. Ignoruj ​​ich.

I wynik

Uruchomienie powyższego kodu

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

Daje ci, developjeśli uruchomisz go z H, a masterjeśli uruchomisz go z I.

Kod jest dostępny jako istota

Joe Chrysler
źródło
24
Usunięto końcowy backtick, który spowodował błąd. Kiedy uruchamiam to polecenie, otrzymuję wiele ostrzeżeń, narzekając na każde powiedzeniecannot handle more than 25 refs
Jon L.
1
@JoeChrysler, czy uważasz, że możesz zrobić jedną linię zamiast 2 i być może sprawić, że będzie działać na Macu, ponieważ acknie jest dostępny na Macu (ktoś sugerował zastąpienie ackgo grep)
nonpolarity
53
Przepraszam, to źle. Oto poprawny, który działał dla mnie:git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
droidbot
15
@droidbot Fajnie, ale wymaga zmiany kolejności potoków, aby uniknąć usunięcia referencji, gdy komunikat grep -v catch commit lub nazwa gałęzi jest częścią innej nazwy gałęzi. git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
gaal
3
@OlegAbrazhaev Nie wiem, czy kiedykolwiek otrzymałeś odpowiedź na swoje pytanie. używając aliasu git: parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"działa dla mnie
mduttondev
111

Możesz także spróbować:

git log --graph --decorate
rcde0
źródło
5
git log --graph --decorate --simplify-by-decorationgdzie --graphjest opcjonalne.
Na13-c
1
git log --graph --decorate --simplify-by-decoration --oneline
anishtain4
106

git rodzic

Możesz po prostu uruchomić polecenie

git parent

aby znaleźć rodzica oddziału, jeśli dodasz odpowiedź @Joe Chrysler jako alias git . Uprości to użytkowanie.

Otwórz plik gitconfig zlokalizowany przy "~/.gitconfig"użyciu dowolnego edytora tekstu. (Dla systemu Linux). W przypadku systemu Windows ścieżka „.gitconfig” zazwyczaj znajduje się pod adresemc:\users\your-user\.gitconfig

vim  ~/.gitconfig

Dodaj następujące polecenie aliasu w pliku:

[alias]
            parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"

Zapisz i zamknij edytor.

Uruchom polecenie git parent

Otóż ​​to!

NIKHIL CM
źródło
5
To świetne rozwiązanie. Przydałoby się również dodać próbki wyjściowe, aby zapewnić oczekiwane wyniki. Kiedy go uruchomiłem, dostałem kilka ostrzeżeń przed ostatnim wierszem, który moim zdaniem był nazwą oddziału macierzystego.
ttemple,
4
Działa jak marzenie! Dla użytkowników systemu Windows .gitconfig zazwyczaj znajduje się pod adresem c: \ users \ your-user \ .gitconfig
zion
12
Uzyskiwanie cannot handle more than 25 refswyjątku.
shajin
czy ktoś może to edytować, aby obsłużyć ostrzeżenie? @ttemple, możesz?
NIKHIL CM
@NIKHILCM działa jak mistrz. Ale mam pytanie, czy rodzic wskazuje, skąd gałąź została utworzona, czy coś jeszcze?
Hariprasath,
52

Mam rozwiązanie twojego ogólnego problemu (określ, czy featurepochodzi on od końcówki develop), ale nie działa przy użyciu opisanej przez ciebie metody.

Możesz użyć, git branch --containsaby wyświetlić listę wszystkich gałęzi pochodzących od końca develop, a następnie użyć, grepaby upewnić się, że featurejest wśród nich.

git branch --contains develop | grep "^ *feature$"

Jeśli jest wśród nich, drukuje " feature"na standardowe wyjście i ma kod powrotu 0. W przeciwnym razie nic nie wydrukuje i będzie miał kod powrotu 1.

Daniel Stutzbach
źródło
1
To działa, ale należy zauważyć, że może to zająć dużo czasu w repozytorium, które ma wiele referencji. To sprawia, że ​​jest trochę mniej niż idealny do wbiegania, np. Haka przed odbiorem.
ebneter
Szukałem gałęzi, nazwiemy ją <branch>tam, gdzie występowałem: git checkout -b <branch-2>od ... To jest odpowiedź! Naprawdę nie potrzeba grepa. git branch --contains <branch>
Poopy McFartnoise
44

Dla mnie to działa dobrze.

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Dzięki uprzejmości odpowiedzi od: @droidbot i @Jistanidiot

Murali Mopuru
źródło
Tak, ale czasami dostajesz „zepsutą fajkę” od grepa.
Vladislav Rastrusny
1
*nie jest właściwym wyrażeniem regularnym do przekazania do grep. Powinien użyć grep -F '*'lub grep '\*'zamiast. W przeciwnym razie dobre rozwiązanie.
arielf
Nie mam wyjścia.
Sandip Subedi
działa dla mnie ....
roottraveller
11

Ponieważ żadna z powyższych odpowiedzi nie działała w naszym repozytorium, chcę udostępnić swój własny sposób, korzystając z najnowszych połączeń git log:

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

Umieść go w skrypcie o nazwie git-last-merges, który akceptuje również nazwę gałęzi jako argument (zamiast bieżącej gałęzi), a także inne git logargumenty

Na podstawie danych wyjściowych możemy ręcznie wykryć gałąź nadrzędną na podstawie własnych konwencji rozgałęziania i liczby połączeń z każdej gałęzi.

EDYCJA: Jeśli git rebaseczęsto korzystasz z gałęzi potomnych (a połączenia są często przewijane do przodu, więc nie ma zbyt wielu zatwierdzeń scalania), ta odpowiedź nie zadziała dobrze, więc napisałem skrypt, aby liczyć przyszłe zatwierdzenia (normalne i scalanie) i za zatwierdzeniami (nie powinno być żadnego scalania za w łączu nadrzędnym) we wszystkich gałęziach w porównaniu z bieżącym. Po prostu uruchom ten skrypt i daj mi znać, czy działa dla Ciebie, czy nie

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n
saeedgnu
źródło
Dzięki. Chociaż może to nie działać zbyt dobrze, jeśli rebaseczęsto używasz (a scalania są fast-forwardczęsto edytowane). Zmienię swoją odpowiedź, jeśli znajdę lepsze rozwiązanie.
saeedgnu
1
Jedyny? odpowiedź do tej pory działała rozsądnie w przypadku, gdy obecna gałąź jest mistrzem. Większość innych rozwiązań dała losowy (i wyraźnie niepoprawny) wynik w tym, co prawda, skrajnym przypadku, w którym nie ma rzeczywistych gałęzi nadrzędnych.
arielf
To jedyna odpowiedź, która zadziałała dla mnie. Aby uzyskać pierwszego rodzica zamiast listy pierwszych 10, możesz użyć tego: git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
lots0logs
10

Rozwiązanie

Rozwiązanie oparte nagit show-branch mnie nie do końca działało (patrz poniżej), więc połączyłem je z rozwiązaniem opartym na tymgit log i skończyłem z tym:

git log --decorate --simplify-by-decoration --oneline \ # selects only commits with a branch or tag
      | grep -v "(HEAD" \                               # removes current head (and branch)
      | head -n1 \                                      # selects only the closest decoration
      | sed 's/.* (\(.*\)) .*/\1/' \                    # filters out everything but decorations
      | sed 's/\(.*\), .*/\1/' \                        # picks only the first decoration
      | sed 's/origin\///'                              # strips "origin/" from the decoration

Ograniczenia i zastrzeżenia

  • HEAD można odłączyć (wiele narzędzi CI robi to, aby zapewnić, że budują poprawne zatwierdzenie w danej gałęzi), ale gałąź źródłowa i gałąź lokalna muszą znajdować się na równi lub „powyżej” bieżącej HEAD.
  • Nie może być żadnych znaczników (przypuszczam; nie testowałem skryptu na zatwierdzeniach ze znacznikiem między gałęzią potomną i nadrzędną)
  • skrypt opiera się na fakcie, „głowa” zawsze jest wymieniony jako pierwszy dekoracji przez logkomendę
  • uruchomiony skrypt na masteridevelop wyniki (w większości) w<SHA> Initial commit

Wyniki

 A---B---D---E---F <-origin/master, master
      \      \
       \      \
        \      G---H---I <- origin/hotfix, hotfix
         \
          \
           J---K---L <-origin/develop, develop
                \
                 \
                  M---N---O <-origin/feature/a, feature/a
                       \   \
                        \   \
                         \   P---Q---R <-origin/feature/b, feature/b
                          \
                           \
                            S---T---U <-origin/feature/c, feature/c

Pomimo istnienia lokalnego oddziału (np. origin/topicJest obecny tylko, ponieważ zatwierdzenie Ozostało wyewidencjonowane bezpośrednio przez jego SHA), skrypt powinien wydrukować w następujący sposób:

  • Dla zatwierdzeń G, H,I (oddział hotfix) →master
  • Dla zatwierdzeń M, N,O (oddział feature/a) →develop
  • Dla zatwierdzeń S, T,U (oddział feature/c) →develop
  • Dla zatwierdzeń P, Q,R (oddział feature/b) →feature/a
  • Dla zatwierdzeń J, K, L(oddział develop) → <sha> Initial commit*
  • Dla zatwierdzeń B, D, E, F(oddział master) →<sha> Initial commit

* - lub masterjeśli developzatwierdzenia byłyby na GŁOWICY mistrza (~ rozwinięcie byłoby szybkie, aby rozwinąć master)


Dlaczego nie pokazałem gałęzi pracy dla mnie

Rozwiązanie oparte nagit show-branch mnie okazało się niewiarygodne w następujących sytuacjach:

  • odłączony HEAD - w tym odłączany futerał na głowę oznacza zastąpienie grep '\*' \„grep”! \ - i to dopiero początek wszystkich kłopotów
  • uruchomiony skrypt na masteridevelop powoduje developi odpowiednio `
  • gałęzie namaster gałęzi ( hotfix/gałęziach) kończą się developjako nadrzędne, ponieważ ich najbliższy masternadrzędny oddział został oznaczony !zamiast z *jakiegoś powodu.
Matt Stuvysant
źródło
2
Tylko odpowiedź, która zadziałała - jako alias git:"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Ian Kemp
8

Pamiętaj, że zgodnie z opisem w „Git: Znajdowanie gałęzi, z której pochodzi zatwierdzenie” , nie możesz łatwo wskazać gałęzi, w której dokonano tego zatwierdzenia (gałęzie można zmienić, przenieść, usunąć ...), nawet jeśli git branch --contains <commit>jest to początek.

  • Możesz wrócić z zatwierdzenia do zatwierdzenia, dopóki git branch --contains <commit>nie wyświetli się lista featuregałęzi i lista developgałęzi,
  • porównaj, które zatwierdzają SHA1 z /refs/heads/develop

Jeśli dwa zatwierdzenia id zgadzają się, możesz iść (to znaczy, że featuregałąź ma swój początek w HEAD develop).

VonC
źródło
6

Magię wiersza poleceń JoeChryslera można uprościć. Oto logika Joe - dla zwięzłości wprowadziłem parametr o nazwie cur_branchzamiast podstawiania poleceń `git rev-parse --abbrev-ref HEAD`w obu wersjach; które można zainicjować w następujący sposób:

cur_branch=$(git rev-parse --abbrev-ref HEAD)

Oto potok Joe:

git show-branch -a           |
  grep '\*'                  | # we want only lines that contain an asterisk
  grep -v "$cur_branch"      | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed

Możemy osiągnąć to samo, co wszystkie pięć z tych pojedynczych filtrów poleceń w stosunkowo prostym awkpoleceniu:

git show-branch -a |
  awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  

To się psuje:

-F'[]^~[]' 

podzielić linię na pola w ], ^, ~oraz [znaków.

/\*/                      

Znajdź linie zawierające gwiazdkę

&& !/'"$cur_branch"'/

... ale nie bieżąca nazwa oddziału

{ print $2;               

Kiedy znajdziesz taką linię, wydrukuj jej drugie pole (czyli część między pierwszym a drugim wystąpieniem naszych znaków separatora pól). W przypadku prostych nazw gałęzi będzie to tylko to, co znajduje się w nawiasach; dla referencji z względnymi skokami będzie to tylko nazwa bez modyfikatora. Nasz zestaw separatorów pól obsługuje zamiar obu sedpoleceń.

  exit }

Następnie wyjdź natychmiast. Oznacza to, że zawsze przetwarza tylko pierwszą pasującą linię, więc nie musimy przepuszczać danych wyjściowych head -n 1.

Mark Reed
źródło
3
Zauważ, że niektóre gałęzie mogą brakować danych wyjściowych z powodu zbyt wielu referencji. Zamiast tego są wyświetlane jako ostrzeżenia na stderr.
Zitrax
5

Oto implementacja PowerShell rozwiązania Marka Reeda:

git show-branch -a | where-object { $_.Contains('*') -eq $true} | Where-object {$_.Contains($branchName) -ne $true } | select -first 1 | % {$_ -replace('.*\[(.*)\].*','$1')} | % { $_ -replace('[\^~].*','') }
chrisevett
źródło
5

Nie twierdzę, że to dobry sposób na rozwiązanie tego problemu, jednak wydaje się, że to działa na mnie.

git branch --contains $(cat .git/ORIG_HEAD) Problem polega na tym, że cat'owanie pliku zagląda do wewnętrznego działania git, więc niekoniecznie jest on zgodny z poprzednimi wersjami (lub poprzedni).

użytkownik1529413
źródło
3

Wdrożenie wieloplatformowe z Ant

    <exec executable="git" outputproperty="currentBranch">
        <arg value="rev-parse" />  
        <arg value="--abbrev-ref" />  
        <arg value="HEAD" />  
    </exec>

    <exec executable="git" outputproperty="showBranchOutput">
        <arg value="show-branch" />  
        <arg value="-a" />  
    </exec>

    <loadresource property="baseBranch">
      <propertyresource name="showBranchOutput"/>
          <filterchain>
            <linecontains>
              <contains value="*"/>
            </linecontains>
            <linecontains negate="true">
              <contains value="${currentBranch}"/>
            </linecontains>
            <headfilter lines="1"/>
            <tokenfilter>
                <replaceregex pattern=".*\[(.*)\].*" replace="\1"/>
                <replaceregex pattern="[\^~].*" replace=""/>
            </tokenfilter>
          </filterchain>
    </loadresource>

    <echo message="${currentBranch} ${baseBranch}" />
ENargit
źródło
2

@ Mark Reed: Powinieneś dodać, że linia zatwierdzenia powinna nie tylko zawierać gwiazdkę, ale zaczynać od gwiazdki! W przeciwnym razie komunikaty zgodności zawierające gwiazdkę są również uwzględniane w dopasowanych wierszach. Tak powinno być:

git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'

lub długa wersja:

git show-branch -a           |
  awk '^\*'                  | # we want only lines that contain an asterisk
  awk -v "$current_branch"   | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed`
ladiko
źródło
2
vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Osiąga te same cele, co odpowiedź Marka Reeda, ale stosuje znacznie bezpieczniejsze podejście, które nie zachowuje się źle w wielu scenariuszach:

  1. Ostatnie zatwierdzenie oddziału nadrzędnego jest scaleniem, dzięki czemu kolumna jest wyświetlana - nie*
  2. Komunikat zatwierdzenia zawiera nazwę oddziału
  3. Wiadomość zatwierdzenia zawiera *
Haoyang Feng
źródło
0

Każdy, kto chce to zrobić w dzisiejszych czasach - aplikacja SourceTree firmy Atlassian pokazuje doskonałą wizualną relację między swoimi oddziałami, tj. Gdzie się zaczęły i gdzie obecnie znajdują się w kolejności zatwierdzania (np. HEAD lub 4 zobowiązania za nimi itp.) .

jake
źródło
0

Jeśli użyjesz drzewa źródeł, spójrz na szczegóły zatwierdzenia> Rodzice> zobaczysz podkreślone numery zatwierdzeń (linki)

Mike6679
źródło
0

Alternatywa: git rev-list master | grep "$(git rev-list HEAD)" | head -1

Uzyskaj ostatni zatwierdzenie, że jest to jednocześnie moja gałąź i master(lub dowolna gałąź, którą chcesz określić)

Alexander Woods
źródło
0

Nie działało to dla mnie, kiedy zrobiłem coś takiego develop > release-v1.0.0 > feature-foo , cofnęłoby się aż do rozwoju, zauważ, że był to rebase, nie jestem pewien, czy to komplikuje mój problem ...

Poniższe dane dały mi poprawny hash zatwierdzenia

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
verdverm
źródło