Git: фиксация нескольких веток одновременно

Я хочу сделать один коммит в разные ветки одновременно, так как в моем проекте у меня разные ветки для разных клиентов.

Скажем, я сделал новый коммит в ветке А. Могу ли я также сделать этот коммит в ветке B, ветке C и D одновременно? Есть ли какая-нибудь команда для этого? Это очень хлопотно, чтобы оформить одну ветку, и каждый раз, когда требуется фиксация во многих ветвях, когда я делаю коммит, это будет для меня кошмаром.

Какой-нибудь простой bash-скрипт для этой операции?

Там есть аналогичный вопрос. но перебазировать это не то, что я хочу.

10 ответов

Функция cherry-pick сделает всю работу и применит только последний коммит:

Учитывая ветви А, Б

git checkout A
git commit -m "Fixed the bug x"
git checkout B
git cherry-pick A

надеюсь это поможет!

Поскольку на мой вопрос нет типичного ответа, я написал простой скрипт для автоматизации этого процесса. Не стесняйтесь комментировать этот код.

#!/bin/bash
BRANCHES=(
master_branch
develop_branch
testing_branch
)
ORIGINALBRANCH=`git status | head -n1 | cut -c13-`
git commit -m $1
CHERRYCOMMIT=`git log -n1 | head -n1 | cut -c8-`
for BRANCH in "${BRANCHES[@]}";
do
    git stash;
    git checkout $BRANCH;
    git cherry-pick $CHERRYCOMMIT;
    git checkout $ORIGINALBRANCH;
    git stash pop;
done

Что-то, на что вы могли бы взглянуть: git stash ваши изменения, git commit, git checkout другая ветвь, git stash apply, git commit, так далее.

Смотрите справочные страницы.

Я думаю, что вы можете написать хэнд после коммита, чтобы объединить или выбрать вишню с другими ветками. Но это, конечно, не будет ни одного коммита.

Hook автоматизирует то, что вы хотите достичь.

http://git-scm.com/docs/githooks

Нет, я не думаю, что ты можешь сделать это. Лучшим вариантом будет зафиксировать коммит в одной из ваших веток (или в основной ветке), а затем либо объединить коммит с другими по одному, либо выбрать коммит в каждую из других веток.

Чтобы одновременно передать несколько веток, просто установите и настройте SourceTree и выберите "Push" и ветви, в которые вы хотите развернуть.

Может быть, это поможет некоторым людям,

Я использовал описанный выше метод "Kit Ho" и добавил его в.gitconfig в качестве псевдонима.

; commitall commits to the current branch as well the all the branches mentionedin BRANCHES array var as shown below.
commitall = "!f()  { \
    BRANCHES=( \
    branches1 \
    branches2 \
    );  \
    usage() \
    { \
        echo \"Usage: git commitall -m 'JIRA: BRANCHNAME:<comment to check in>'\"; \
        exit 1; \
    }; \
    OPTIND=1; \
    DFNs=\"\"; \
    while getopts \"h:m:\" opt; \
    do \
        case \"$opt\" in \
            h) \
            usage; \
            ;; \
            m)  export Comment=$OPTARG; \
            ;; \
        esac; \
    done; \
    ORIGINALBRANCH=`git symbolic-ref HEAD|cut -d/ -f3- `; \
    echo \"Current branch is $ORIGINALBRANCH \" ; \
    echo $Comment | grep \"^JIRA: $ORIGINALBRANCH:\"  > /dev/null 2>&1 ; \
    if [ $? -ne 0 ]; then \
        usage; \
    fi; \
    LOGMSG=`git log -1 --pretty=%B --grep=\"JIRA: $ORIGINALBRANCH:\" `; \
    MSG='commit first time in this branch is a success' ; \
    if [ \"$LOGMSG\" == \"\" ]; then \
        git commit -m \"$Comment\"; \
    else \
        git commit -a --amend -C HEAD; \
        MSG='commit with amend succeeded' ; \
    fi; \
    if [ $? -ne 0 ]; then \
        echo \"git commit failed!\"; \
        exit 1; \
    else \
        echo \"$MSG\" ; \
    fi; \
    CHERRYCOMMIT=`git log -n1 | head -n 1 | cut -c8- ` ; \
    if [ \"$CHERRYCOMMIT\" == \"\" ]; then \
        echo \"'git log -n1 | head -n 1 | cut -c8-' no commits for this branch\"; \
        exit 1; \
    fi; \
    echo \"found this commit -> $CHERRYCOMMIT for current branch\"; \
    stashes=`git stash list | grep \"WIP on $ORIGINALBRANCH\" ` ; \
    for BRANCH in \"${BRANCHES[@]}\"; do \
        if [ \"$stashes\" ]; then \
            git stash; \
        fi;\
        git checkout $BRANCH; \
        if [ $? -ne 0 ]; then \
            echo \"git checkout $BRANCH failed!\"; \
            exit 1; \
        fi; \
        git cherry-pick $CHERRYCOMMIT; \
        git checkout $ORIGINALBRANCH; \
        if [ \"$stashes\" ]; then \
            git stash pop; \
        fi; \
    done; \
    }; \
f"

Я не думаю, что есть способ к этому. Может быть, вам нужно написать скрипт для bash или сделать другое репо для разных веток.

Это может зависеть от того, как вы собираетесь выдвигать свои коммиты. Я имею в виду, что у вас всегда есть возможность протолкнуть несколько веток одним git push команда.

Сделайте следующее .git/config настройки, чтобы гарантировать, что master ветвь всегда будет подталкивать к foobar филиал тоже.

[remote "origin"]
        url = git@github.com:mgerhardy/example.git
        fetch = +refs/heads/*:refs/remotes/origin/*
        push = refs/heads/master:refs/heads/master
        push = refs/heads/master:refs/heads/foobar 

Но проблема здесь может заключаться в том, что если эти две ветви расходятся, вы не можете их подтолкнуть. Вы по-прежнему можете реорганизовать свой код, который определяется вашим клиентом на основе ветви, которую вы строите. Таким образом, вы можете поддерживать десятки клиентов и всегда синхронизировать все ветви.

Вы также можете сделать хорошую автоматизацию, используя немного Python:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Populate specified or latest commit across all branches in the repository.

"""

import os
import re
import sys
import sh


git = sh.git.bake(_cwd=os.curdir)

if len(sys.argv) > 1:
    if '-h' in sys.argv or '--help' in sys.argv:
        print('Usage: git-populate.py [commit] [-h|--help]')
        sys.exit(0)
    else:
        commit = sys.argv[1]
else:
    # By default choose latest commit.
    git_log = git('--no-pager', 'log', '-n', '1', '--no-color').stdout
    commit = re.search(r'[a-f0-9]{40}', git_log).group()

print('Commit to be populated: {0:.6s}'.format(commit))

git_branch = git.branch('-a', '--no-color').stdout
source_branch = re.search(r'\*\s(\w+)$', git_branch, re.MULTILINE).group(1)
print('Source branch: {0}'.format(source_branch))

branches = re.findall(r'remotes/\w+/([\w-]+)$', git_branch, re.MULTILINE)
# Exclude current branch from target branches.
branches = [i for i in branches if i != source_branch]
print('Target branches: {0}'.format(branches))


print('Stashing local changes')
git_stash = git.stash().stdout

for branch in branches:
    print('Ading commit {0:.6s} to branch {1}'.format(commit, branch))
    git.checkout(branch)
    try:
        result = git('cherry-pick', commit)
    except sh.ErrorReturnCode_1:
        # Ignore diplicate cherry pick and discard changes.
        git.reset()


git.checkout(source_branch)
print('Return to branch {0}'.format(source_branch))

if not git_stash.startswith('No local changes to save'):
    print('Restoring local changes')
    git.stash.pop()
Другие вопросы по тегам