简体   繁体   中英

Can I have two tracking branches in Git (separate for push and rebase)?

The workflow in my team is as follows:

  • At any time, we have more than one active branch; the development lands in 2 or more branches in parallel, for two different versions of an application (let's say, v4 for the version to-be-released soon, and v5 , to-be-released in distant future). We regularly merge v4 into v5 .
  • No one ever works directly on v4 or v5 , we work on feature branches in our forks and create pull requests, pointing either to upstream v4 or v5 (using Atlassian Stash)

Let's say I create a new development. I create a new branch:

git checkout -b SOMETHING_FOR_V4 v4

Now I'm in SOMETHING_FOR_V4 . I do commits and push:

git push -u origin SOMETHING_FOR_V4

I've set the remote tracking branch with -u so the next time I update something, I can do git push without specifying branch and Git will know where to push.

However time has passed and I want to rebase.

I need to explicitly tell git rebase origin/v4

Contrary, I could set origin/v4 to my tracking branch at branch creation time, but then, when I push, I would have to always say git push origin SOMETHING_FOR_V4 every time.

What I'd like to have is so that Git is intelligent enough to know on top of which to rebase. If I just said git rebase after doing git push -u , it would take the remote tracking branch I specified when pushing, this is not what I want.

Basically I want to have separate tracking branch used for git push (the one I push to the first time) and separate one for git rebase (rebase on top of v4 or v5 depending from which I started [1]).

Is it possible to get this kind of behavior?

Alternatively, what command would I use to find out myself whether I am "closer" to v4 or v5 (I am thinking about automating fetch-and-rebase in an alias)?

[1] it could either rebase on top of what I started off from, say v4 , or its remote, in this scenario origin/v4 . Let's say I can handle keeping v4 and origin/v4 in sync myself.

As it stands there is no built-in way to achieve what you are trying to do. But git wouldn't be git if you weren't able to handle this case yourself.

Configuration

For this to function we have to configure the branch on which we want to rebase. Git gives you free hand in adding any configuration you can imagine; so let's call this configuration key branch.<name>.rebase-upstream .

To set origin/v4 as the rebase-upstream for SOMETHING_FOR_V4 we can simply do:

git configure branch.SOMETHING_FOR_V4.rebase-upstream origin/v4

Shell script

Now we need a script which reads this configuration and passes it to rebase .

The following script will try to read the configuration for the current branch; it will warn you if you aren't on any branch right now or if no rebase-upstream configuration exists for the current branch.

#!/bin/sh

current_branch="$(git symbolic-ref --short -q HEAD)"
if [ $? == 1 ]; then
    echo "You are on no branch!" >&2
    exit 1
fi

upstream="$(git config --get branch.$current_branch.rebase-upstream)"
if [ $? == 1 ]; then
    echo "No rebase-upstream reference configured for $current_branch (config: branch.$current_branch.rebase-upstream)" >&2
    exit 1
fi

echo "Rebase $current_branch onto $upstream"
git rebase "$upstream"

Usage

To easily use this script you now have two possibilities.

You either add the script somewhere in your path and call it git-rebase-upstream (or similar); the leading git- is the important part here. Git looks for executables in your path which start with git- and makes them available as command. Now you can use it via git rebase-upstream .

The more "portable" approach would add an alias which contains a shell function with the script. The advantage being that you only have to backup your global .gitconfig if you want to synchronize your git configuration and commands accross multiple machines.

Adding an alias called rebase-upstream would look like this:

git config --global alias.rebase-upstream '!f() { current_branch="$(git symbolic-ref --short -q HEAD)"; if [ $? == 1 ]; then echo "You are on no branch!" >&2; exit 1; fi; upstream="$(git config --get branch.$current_branch.rebase-upstream)"; if [ $? == 1 ]; then echo "No rebase-upstream reference configured for $current_branch (config: branch.$current_branch.rebase-upstream)" >&2; exit 1; fi; echo "Rebase $current_branch onto $upstream"; git rebase "$upstream"; }; f'

If you want to use a shorter alias ( ru ) for either approach you can use

git config --global alias.ru '!git rebase-upstream'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM