729 votes

Fusionner, mettre à jour et tirer les branches Git sans utiliser les extractions

Je travaille sur un projet qui a 2 branches, A et B. en général, je travail sur Une branche, et de fusionner des choses de la direction de B. Pour la fusion, je la ferait:

git merge origin/branchB

Cependant, je tiens également à conserver une copie locale de la branche B, comme je l'ai peut vérifier à l'occasion de la branche sans la première fusion avec ma direction de A. Pour cela, je souhaiterais faire:

git checkout branchB
git pull
git checkout branchA

Est il possible de le faire ci-dessus en une seule commande, et sans avoir à changer de branche d'avant en arrière? Dois-je utiliser git update-ref ? Comment?

1117voto

Cupcake Points 22154

La Réponse Courte

Tant que vous êtes en train de faire une avance rapide de fusion, alors vous pouvez simplement utiliser

git fetch <remote> <sourceBranch>:<destinationBranch>

Exemples:

# 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

Tandis que l'Ambre de la réponse va également travailler dans des fast-forward cas, l'utilisation d' git fetch de cette façon, au contraire, est un peu plus sûr que juste la force-déplacement de la branche de référence, depuis git fetch sera automatiquement empêcher l'activation accidentelle de la non-avancer rapidement aussi longtemps que vous n'utilisez pas l' + dans le refspec.

La Réponse Longue

Vous ne pouvez pas fusionner une branche B en direction de Un sans de regarder d'abord si elle entraînerait une non-avance rapide de fusion. C'est parce que d'une copie de travail est nécessaire pour résoudre les conflits potentiels.

Toutefois, dans le cas de fast-forward fusionne, c'est possible, parce que de telles fusions ne peut jamais entraîner dans des conflits qui, par définition. Pour ce faire consulter sans une direction tout d'abord, vous pouvez utiliser git fetch avec un refspec.

Voici un exemple de la mise à jour de master (interdisant aux non-avance rapide des changements) si vous avez une autre branche feature extrait:

git fetch upstream master:master

Ce cas d'utilisation est si commune, que vous aurez probablement envie de faire un alias dans votre fichier de configuration de git, comme celui-ci:

[alias]
    sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'

Ce que cet alias n'est la suivante:

  1. git checkout HEAD: cela met votre copie de travail détaché de la tête de l'état. Ceci est utile si vous voulez mettre à jour master tandis que vous arrive d'être contrôlé. Je pense qu'il était nécessaire de le faire avec parce que sinon, la branche de référence pour l' master ne bougera pas, mais je ne me souviens pas si c'est vraiment bon de réduction-le-haut de ma tête.

  2. git fetch upstream master:master: cette avance de votre région master à la même place qu' origin/master.

  3. git checkout - vérifie préalablement extrait de la branche (c'est ce que l' - dans ce cas).

La syntaxe de l' git fetch de (non-)avance rapide fusionne

Si vous voulez l' fetch commande échoue si la mise à jour est non-rapide-vers l'avant, alors il suffit d'utiliser un refspec de la forme

git fetch <remote> <remoteBranch>:<localBranch>

Si vous voulez autoriser les non-avance rapide des mises à jour, puis vous ajoutez un + à l'avant de la refspec:

git fetch <remote> +<remoteBranch>:<localBranch>

Notez que vous pouvez passer votre local pensions que la "distance" paramètre à l'aide de .:

git fetch . <sourceBranch>:<destinationBranch>

La Documentation

De la git fetch documentation qui explique cette syntaxe (l'emphase est mienne):

<refspec>

Le format d'un <refspec> paramètre est une option de plus +, suivie par la source ref <src>, suivie par un colon :, suivie par la destination ref <dst>.

La distance ref qui correspond <src> est rapportée, et si <dst> n'est pas une chaîne vide, le ref qui correspond à ce rapide est transmis à l'aide de <src>. Si l'option plus + est utilisé, la ref est mis à jour, même si elle n'aboutit pas à une avance rapide de mise à jour.

Voir Aussi

  1. Git checkout et de fusion, sans toucher à l'arbre de travail

  2. La fusion sans changer le répertoire de travail

86voto

Amber Points 159296

Non, il n'est pas. Une extraction de la branche cible est nécessaire pour vous permettre de résoudre les conflits, entre autres choses (si Git est pas en mesure de fusionner automatiquement).

Toutefois, si la fusion est celui qui serait l'avance rapide, vous n'avez pas besoin de vérifier la branche cible, parce que vous n'avez pas réellement besoin de fusionner tout - tout ce que vous avez à faire est de mettre à jour la branche pour pointer vers le nouveau chef réf. Vous pouvez faire cela avec git branch -f:

git branch -f branch-b branch-a

Sera mise à jour, branch-b de pointer à la tête de branch-a.

31voto

Jefromi Points 127932

Que l'Ambre a dit, d'avance rapide, de fusions sont le seul cas dans lequel vous pourrait éventuellement le faire. Toute autre fusion éventuellement besoin d'aller à travers l'ensemble des trois voies de fusion, l'application de correctifs, la résolution de conflits affaire - et cela signifie qu'il faut être de fichier.

Il m'arrive d'avoir un script, j'ai utiliser pour exactement cela: faire de l'avance rapide fusionne sans toucher le travail de l'arbre (sauf si vous êtes fusion en TÊTE). C'est un peu long, parce que c'est au moins un peu robuste - il vérifie pour s'assurer que la fusion serait une avance rapide, puis effectue sans vérification de la direction générale, mais de produire les mêmes résultats que si vous l'aviez - vous voir l' diff --stat résumé des changements, et l'entrée dans le reflog est exactement comme une avance rapide de fusion, au lieu de "reset" celui que vous obtenez si vous utilisez branch -f. Si vous nommez git-merge-ff et déposez-le dans votre répertoire bin, vous pouvez l'appeler comme une commande 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. Si quelqu'un voit des problèmes avec le script, s'il vous plaît commentaire! C'était une écriture-et-oublier de travail, mais je serais heureux de les améliorer.

20voto

Jefromi Points 127932

Vous pouvez faire cela seulement si la fusion est un fast-forward. Si elle ne l'est pas, puis git doit avoir les extraits des fichiers de sorte qu'il peut fusionner!

Pour faire une avance rapide seulement:

git fetch <branch that would be pulled for branchB>
git update-ref -m "merge <commit>: Fast forward" refs/heads/<branch> <commit>

<commit> est la prochaine commettre, celui que vous voulez pour effectuer une avance rapide. C'est fondamentalement comme l'utilisation d' git branch -f pour déplacer la branche, sauf qu'il enregistre également dans le reflog comme si vous avez déjà fait de la fusion.

S'il vous plaît, s'il vous plaît, veuillez ne pas le faire pour quelque chose qui n'est pas un fast-forward, ou vous aurez juste être la réinitialisation de votre branche à l'autre de la validation. (Pour vérifier, voir si git merge-base <branch> <commit> donne de la direction générale SHA1.)

11voto

kkoehne Points 89

Une autre manière, certes, assez brute est de simplement recréer la branche:

 git fetch remote
git branch -f localbranch remote/remotebranch
 

Cela rejette la branche périmée locale et en recrée une avec le même nom, donc utilisez-la avec soin ...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X