4

I am using the "Integration-Manager" workflow with Git, while using gitolite for permission management. Gitolite has this neat option for easily managing personal user branches in:

refs/personal/USERNAME/USERBRANCHNAME

In our case, these are the only branches to which the developers have write access. This means they are routinely pulling from the "blessed" repository, which is the "master" branch on the "origin" remote, like so:

$ git pull origin master

However, they need to routinely push their work back up to their personal branches, like so:

$ git push origin master:refs/personal/mysuername/mybranchname

Typing those long branch names gets old, really fast, especially for the integrator, who is having to pull routinely from various, long branch names. Most people want to type something simpler, like:

$ git push origin master:mybranchname

So, my question is, "How do I make this easier with shorter names and reduced typos?" Is there some way to create an alias or shortcut for the user's remote branch? Our integrator would like to be able to create aliases for each of the developers to simplify her commands also.

Also, is it possible to configure git to always pull from one branch and push to a different branch without having to specify the remote and branch names in both cases? This would help our developers, although it would not help our integrator. ... I'm familiar with configuring a single default to push and pull from the same remote and branch, but that does not work in this case, since the push and pull branches are different.

Thanks!

Community
  • 1
  • 1
Trevor
  • 1,613
  • 3
  • 22
  • 34

3 Answers3

4

Yes. Just track the branch with one of a different name. See the manual page for git branch and things like --set-upstream.

Hope this helps.

Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
  • Exactly this. Git has this whole thing called tracking. The local branch name doesn't have to match the remote, you can set up your local branch to track origin/master and then `git push` is all you'll need. – user229044 Sep 08 '11 at 23:40
  • But, doesn't this road require the regular "pull" source and "push" destination to be the same? Our users will be regularly pulling from one branch and pushing to another. ... Thanks! Maybe I misunderstood? – Trevor Sep 14 '11 at 19:41
  • sorry to be dense, but I've read the man pages for `git branch, remote, clone, and push` several times, and I still don't get it. :( If a developer does a clone: `git clone remote-host:repo-name` Where, 'master' is the primary branch for the remote, she would pull down future updates like so: `git pull origin master` or `git pull`. That's good. I got that. But, she always pushes her work up to `git push origin master:refs/personal/USERNAME/USERBRANCHNAME`. What does she need to do, so she only has to do `git push` in the future? – Trevor Sep 16 '11 at 02:14
  • add the --set-upstream parameter – Adam Dymitruk Sep 16 '11 at 18:27
1

Note: The following ignores gitolite because I don't know how it works.

Instead of tracking the master branch, each developer could track their own personal branch. When they want updates, they can merge them from the master. (It sounds like your current setup is the opposite: Everyone tracks master and is pushing manually.)

Also, don't forget about tab completion. For me on Ubuntu using bash, typing git push origin o<TAB> will complete to origin/ and then another Tab will show a list of available branches.


Create personal branches

If your integrator has the repo checked out into ~/prj:

integrator:~/prj$ git push origin master:trevor-personal
integrator:~/prj$ git push origin master:pydave-personal

Setup the developer's repos

Each developer can clone using their personal branch.

trevor:~$ git clone /path/to/master/repo.git -b trevor-personal prj
pydave:~$ git clone /path/to/master/repo.git -b pydave-personal prj

Or they can checkout a new branch in their existing clone that tracks their personal branch on origin.

pydave:~/prj$ git checkout -b personal origin/pydave-personal 

Alternatively, we could use set-upstream if we want to use an existing branch.

pydave:~/prj$ git branch --set-upstream personal origin/pydave-personal  

Workflow

Post a change to developer branch.

trevor:~/prj$ git commit -am'changed something'
trevor:~/prj$ git push

Merge it.

integrator:~/prj$ git pull
integrator:~/prj$ git push origin origin/trevor-personal:master

Retrieve changes from master branch. (We have to be specific about using origin's master. git pull will just merge changes in pydave-personal

pydave:~/prj$ git pull origin master
idbrii
  • 10,975
  • 5
  • 66
  • 107
  • Thanks for the detailed suggestions! BTW, gitolite uses ssh. ... Trying to apply your suggestions to my situation, if my integrator pushes the "blessed" branch for a developer, like so: `git push origin master:refs/personal/DEVELOPER/FROM_INTEGRATOR`, this appears to create a new branch on the remote repo. However, the developer is unable to clone it: `git clone remote-host:repo-name -b refs/personal/DEVELOPER/FROM_INTEGRATOR`, produces: `cloning into repo-name ... warning: Remote branch refs/personal/DEVELOPER/FROM_INTEGRATOR not found in upstream origin, using HEAD instead`. ??? – Trevor Sep 16 '11 at 02:30
1

Thanks to all for the input and suggestions. Here's how I got my developers and integrators to use bare git push and git pull:

For The Developer

In the simplest integration-manager workflow, as described above, the developer has cloned (git clone) and is therefore automatically tracking the remote master branch in her local master branch, so all she needs is:

git pull

To update her local master branch. If she is working in some other branch, then she can update the upstream branch that is is tracking, as Adam suggested:

git branch --set-upstream MYOLDBRANCH origin/master
# or, use longer, more explicit syntax, like:
git branch --set-upstream MYOLDBRANCH refs/remotes/origin/master

The tracked branch (origin/master, in this case) will be pulled by default.

Since the default push target is a different branch and not the same name, we cannot take advantage of the push.default being: tracking, current, or matching. Instead, our developer must set the default source:destination refspec for all pushes to a given remote in her .git/config file, like so:

[remote "origin"]
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = GITREPOHOSTNAME:REPONAME
        push = master:refs/personal/MYDEVNAME/MYBRANCHNAME

She could also create an alias, like so:

git config alias.pushToMyBr 'push origin master:refs/personal/MYDEVNAME/MYBRANCHNAME

Aliases are very powerful and offer the ultimate flexibility in avoiding keystrokes. :-) The above case can be executed with a simple:

git pushToMyBr

For The Integrator

In this simple case, the integrator usually pushes to one place, origin/master. If the push.default is set to matching, tracking, or current, then a bare push will work, like so:

git config push.default current
git checkout master
git push

The frequent pull from various personal developer branches is the more difficult case. The integrator can use aliases to simplify the task, like so:

git config alias.pullFromXY 'pull origin refs/personal/DEVNAMEX/BRANCHNAMEY:master
# or, pull to a specific topic branch
git config alias.pullFromABtoC 'pull origin refs/personal/DEVNAMEA/BRANCHNAMEB:branchC'

The integrator can also create branches to track the developer's personal remote branches, like so:

git checkout -b test_devXbranchY origin/personal/DEVNAMEX/BRANCHNAMEY
# or, use a more specific syntax:
git checkout -b test_devXbranchY refs/remotes/origin/personal/DEVNAMEX/BRANCHNAMEY

For this to work, the integrator must add personal branches to her fetch list. This can be accomplished by directly editing her .git/config, like so: (I don't know how to do this with a git-config or any other git command.)

[remote "origin"]
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = MYGITHOSTNAME:MYREPONAME
        fetch = +refs/personal/*:refs/remotes/origin/personal/*
        # Fetch a specific developer's branches:
        fetch = +refs/personal/devX/*:refs/remotes/origin/personal/devX/*

Thanks to all for the help! Hope this helps someone else who uses gitolite and personal branches outside of head-space.

Thanks!

Trevor

Trevor
  • 1,613
  • 3
  • 22
  • 34