611 Stimmen

So finden Sie den nächstgelegenen Elternteil eines Git-Zweigs

Nehmen wir an, ich habe das folgende lokale Repository mit einem Commit-Baum wie diesem:

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

master ist mein dies ist der neueste stabile Release-Code , develop ist mein dies ist der "nächste" Freigabecode und feature ist eine neue Funktion, die in Vorbereitung ist für develop .

Mit Hilfe von Hooks möchte ich Pushes verweigern können an feature in mein entferntes Repository zu übertragen, es sei denn f ist ein direkter Abkömmling von develop HEAD. D.h. der Commit-Baum sieht so aus, weil das Feature git rebase auf d .

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

Ist es also möglich,:

  • Identifizieren Sie den übergeordneten Zweig von feature ?
  • Identifizieren Sie die Übertragung im übergeordneten Zweig, die f ist ein Nachkomme von?

Von dort aus würde ich prüfen, was HEAD des übergeordneten Zweigs ist, und sehen, ob f Vorgänger mit dem übergeordneten Zweig HEAD übereinstimmt, um festzustellen, ob das Merkmal neu geordnet werden muss.

4voto

ladiko Punkte 87

Mark Reeds Lösung ist im Wesentlichen korrekt. Beachten Sie jedoch, dass die Commit-Zeile nicht nur ein Sternchen enthalten, sondern auch mit einem Sternchen beginnen sollte! Andernfalls werden auch Commit-Nachrichten, die einen Stern enthalten, in die übereinstimmenden Zeilen aufgenommen. Es sollte also lauten:

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

oder die lange Version:

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`

0 Stimmen

Meinten Sie in der Langfassung s/awk/grep/ ?

4voto

Justin Grote Punkte 113

Hier ist meine PowerShell-Version:

function Get-GHAParentBranch {
    [CmdletBinding()]
    param(
        $Name = (git branch --show-current)
    )
    git show-branch |
      Select-String '^[^\[]*\*' |
      Select-String -NotMatch -Pattern "\[$([Regex]::Escape($Name)).*?\]" |
      Select-Object -First 1 |
      Foreach-Object {$PSItem -replace '^.+?\[(.+)\].+$','$1'}
}

1 Stimmen

Hallo! Während dieser Code kann die Frage zu lösen, einschließlich einer Erläuterung wie und warum dies das Problem löst, würde wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr "Up-Votes" führen. Denken Sie daran, dass Sie die Frage für künftige Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten fügen Sie Ihrer Antwort Erklärungen hinzu und geben Sie an, welche Einschränkungen und Annahmen gelten.

3voto

Victor Mataré Punkte 2169

Ich mochte die vielen unsicheren Annahmen nicht, die in den Lösungen enthalten sind, die komplexe Textausgaben analysieren, also wollte ich eine robustere Lösung mit weniger Annahmen über halbstrukturierte Daten:

# Search backwards in history for the first commit that is in a branch other than $1
# and output that branch's name.
parent_branch() {
    local result rev child_branch=$1
    rev=$(git rev-parse --revs-only $child_branch)
    while [[ -n $rev ]]; do
        result=$(git branch --contains $rev | grep -v " $child_branch$")
        if [[ -n $result ]]; then
            echo $result
            return 0
        fi
        rev=$(git rev-parse --revs-only $rev^)
    done
    return 1
}

Achtung: Da dies iterativ rückwärts in der Historie abläuft, wird bei jeder Übertragung nach der ersten gesucht, die in einem anderen Zweig liegt als $1 Je länger Ihr Zweig wird, desto teurer wird er. Aber da Zweige normalerweise sowieso relativ kurzlebig sind, sollte das kein allzu großes Problem sein.

Beachten Sie auch, dass ich die git branch --contains Damit lassen sich auch Zweige finden, die eine gemeinsame Basis haben, aber bereits darüber hinausgegangen sind. Um nur Zweige zu finden, die genau auf die gemeinsame Basis zeigen, verwenden Sie git branch --points-at .

2voto

ENargit Punkte 594

Plattformübergreifende Implementierung mit 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}" />

1 Stimmen

Eine Erklärung wäre angebracht. Z. B.: Was ist die Idee/der Sinn?

1voto

CDuv Punkte 1940

Eine Shell-Funktion, die den ersten Commit in mehr als einem Zweig sucht:

# Get the first commit hash of a given branch.
# Uses `git branch --contains` to backward (starts from HEAD) check each commits
# and output that branch's name.
first_commit_of_branch() {
    if [ $# -ne 1 ] || [ -z "${1}" ] ; then
        (>&2 echo "Error: Missing or empty branch name.")
        (>&2 echo "Usage: $0 branch_to_test")
        return 2
    fi
    local branch_to_test="${1}"; shift
    local commit_index_to_test
    local maximum_number_of_commit_to_test
    local branch_count_having_tested_commit

    git rev-parse --verify --quiet "${branch_to_test}" 2>&1 > /dev/null || {
        (>&2 echo "Error: Branch \"${branch_to_test}\" does not exists.")
        return 2
    }

    commit_index_to_test=0
    maximum_number_of_commit_to_test=$(git rev-list --count "${branch_to_test}")

    while [ ${commit_index_to_test} -le ${maximum_number_of_commit_to_test} ] ; do
        # Testing commit $branch_to_test~$commit_index_to_test…

        # If it fails, it means we tested all commits from the most recent of
        # branch $branch_to_test to the very first of the git DAG. So it must be it.
        git rev-parse --verify --quiet ${branch_to_test}~${commit_index_to_test} 2>&1 > /dev/null || {
            git rev-list --max-parents=0 "${branch_to_test}"
            return 0
        }

        branch_count_having_tested_commit="$( \
            git --no-pager branch --no-abbrev --verbose \
                --contains ${branch_to_test}~${commit_index_to_test} \
            | cut -c 3- \
            | cut -d ' ' -f 2 \
            | wc -l \
        )"

        # Tested commit found in more than one branch
        if [ ${branch_count_having_tested_commit} -gt 1 ] ; then
            if [ ${commit_index_to_test} -eq 0 ]; then
                (>&2 echo "Error: The most recent commit of branch \"${branch_to_test}\" (${branch_to_test}~${commit_index_to_test}) is already in more than one branch. This is likely a new branch without any commit (yet). Cannot continue.")
                return 1
            else
                # Commit $branch_to_test~$commit_index_to_test is in more than
                # one branch, stopping there…
                git rev-parse ${branch_to_test}~$((commit_index_to_test-1))
                return 0
            fi
        fi
        # else: Commit $branch_to_test~$commit_index_to_test is still only in
        #       branch ${branch_to_test} continuing…"
        commit_index_to_test=$((commit_index_to_test+1))
    done
}

Achtung: Er schlägt fehl, wenn er auf einem Zweig ausgeführt wird, der einen Unterzweig hat und seit dem keine neue Übergabe stattgefunden hat.

A---B---C---D      <- "main" branch
 \   \
  \   E---F        <- "work1" branch
   \       \
    \       G---H  <- "work1-b" branch
     \
      I---J        <- "work2" branch

first_commit_of_branch main # C
first_commit_of_branch work1 # (Fails)
first_commit_of_branch work1-b # G
first_commit_of_branch work2 # I

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X