* Best "triangle" workflow setup?
@ 2017-05-11 19:41 Robert Dailey
2017-05-11 20:17 ` Jeff King
0 siblings, 1 reply; 6+ messages in thread
From: Robert Dailey @ 2017-05-11 19:41 UTC (permalink / raw)
To: Git
I know Git has evolved to support the "triangle" workflow model in
different ways, with the goal of making it better. However because
there are so many different options from separate push URLs for
remotes to various ways to manage tracking branches, it's not clear to
me which specific configuration suits this workflow the best.
So my situation is that I have 3 repositories: The original upstream
repository, a fork of that repository (also remote), and my local
clone of the upstream repository.
What I want (as a default) is for `git pull` to pull from the
same-named branch on the upstream repository, but for `git push` to
push to the same-named branch on the fork repository. However to
override this behavior for when I want to push directly to upstream
repo, I should be able to use an explicit `git push origin my-topic`
(but `git push` by default will act as `git push fork my-topic`).
What is the best way to achieve this? Is there a different workflow
from what I'm imagining that works a little better (in other words, I
don't need it to work *exactly* as I've described, mainly I just want
to avoid accidentally pushing changes to the upstream repo in the
default case when I want to push to the fork instead for pull
request)?
Thanks in advance for any advice.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Best "triangle" workflow setup?
2017-05-11 19:41 Best "triangle" workflow setup? Robert Dailey
@ 2017-05-11 20:17 ` Jeff King
2017-05-11 21:23 ` Robert Dailey
0 siblings, 1 reply; 6+ messages in thread
From: Jeff King @ 2017-05-11 20:17 UTC (permalink / raw)
To: Robert Dailey; +Cc: Git
On Thu, May 11, 2017 at 02:41:41PM -0500, Robert Dailey wrote:
> What I want (as a default) is for `git pull` to pull from the
> same-named branch on the upstream repository, but for `git push` to
> push to the same-named branch on the fork repository. However to
> override this behavior for when I want to push directly to upstream
> repo, I should be able to use an explicit `git push origin my-topic`
> (but `git push` by default will act as `git push fork my-topic`).
I think you want:
[push]
default = current
[remote]
pushDefault = myfork
to make "git push" do what you want. And then generally have branches
mark their counterparts on "origin" (which you can do either at creation
time, or probably by using "git push -u origin my-topic" when you push
them).
This is similar to what I do for my git.git workflow, though I usually
have origin/master as the branch's upstream. I.e., I'd create them with:
git checkout -b my-topic origin
And then rebasing always happens on top of master (because "origin"
doesn't even have my topic branch at all). If I want to compare with
what I've pushed to my fork, I'd use "@{push}".
-Peff
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Best "triangle" workflow setup?
2017-05-11 20:17 ` Jeff King
@ 2017-05-11 21:23 ` Robert Dailey
2017-05-11 23:36 ` Jeff King
0 siblings, 1 reply; 6+ messages in thread
From: Robert Dailey @ 2017-05-11 21:23 UTC (permalink / raw)
To: Jeff King; +Cc: Git
On Thu, May 11, 2017 at 3:17 PM, Jeff King <peff@peff.net> wrote:
> I think you want:
>
> [push]
> default = current
> [remote]
> pushDefault = myfork
>
> to make "git push" do what you want. And then generally have branches
> mark their counterparts on "origin" (which you can do either at creation
> time, or probably by using "git push -u origin my-topic" when you push
> them).
So without the `pushDefault` setting, `current` will default to a
remote named `origin` if there is no tracking branch set, correct? So
`pushDefault` is effectively overriding this built-in default? In
addition, it seems like since this overrides `branch.name.remote`,
that this effectively makes the remote tracking branch *only* for
`pull`. Is this a correct understanding?
> This is similar to what I do for my git.git workflow, though I usually
> have origin/master as the branch's upstream. I.e., I'd create them with:
>
> git checkout -b my-topic origin
I'm looking through the `git checkout` and `git branch` documentation,
but I don't see any mention of it being valid to use a remote name as
the <start-point> parameter (you're using `origin` in the above
example). Am I misunderstanding? Did you mean origin/my-topic?
> And then rebasing always happens on top of master (because "origin"
> doesn't even have my topic branch at all). If I want to compare with
> what I've pushed to my fork, I'd use "@{push}".
Can you explain more about how your rebase chooses master instead of
your same-named remote tracking branch? Maybe provide some examples of
your rebase command and respective configuration (unless what you've
already provided is sufficient). As for @{push}, I haven't used this
before, so I'll dig in the docs and learn about it.
Thanks for your advice, so far I like this direction but seems like
there is more for me to learn!
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Best "triangle" workflow setup?
2017-05-11 21:23 ` Robert Dailey
@ 2017-05-11 23:36 ` Jeff King
2017-05-12 14:53 ` Robert Dailey
0 siblings, 1 reply; 6+ messages in thread
From: Jeff King @ 2017-05-11 23:36 UTC (permalink / raw)
To: Robert Dailey; +Cc: Git
On Thu, May 11, 2017 at 04:23:03PM -0500, Robert Dailey wrote:
> On Thu, May 11, 2017 at 3:17 PM, Jeff King <peff@peff.net> wrote:
> > I think you want:
> >
> > [push]
> > default = current
> > [remote]
> > pushDefault = myfork
> >
> > to make "git push" do what you want. And then generally have branches
> > mark their counterparts on "origin" (which you can do either at creation
> > time, or probably by using "git push -u origin my-topic" when you push
> > them).
>
> So without the `pushDefault` setting, `current` will default to a
> remote named `origin` if there is no tracking branch set, correct? So
> `pushDefault` is effectively overriding this built-in default? In
> addition, it seems like since this overrides `branch.name.remote`,
> that this effectively makes the remote tracking branch *only* for
> `pull`. Is this a correct understanding?
Right. The general idea of a triangular workflow is that where you pull
from is not the same as where you push to. We have branch.*.pushremote
if you really wanted to do it on a per-branch basis, but in my
experience you almost always want to use "myfork", because you can't
push to "origin" in the first place. :)
> > This is similar to what I do for my git.git workflow, though I usually
> > have origin/master as the branch's upstream. I.e., I'd create them with:
> >
> > git checkout -b my-topic origin
>
> I'm looking through the `git checkout` and `git branch` documentation,
> but I don't see any mention of it being valid to use a remote name as
> the <start-point> parameter (you're using `origin` in the above
> example). Am I misunderstanding? Did you mean origin/my-topic?
Using "origin" there will resolve to "origin/HEAD", i.e., origin/master.
So basically I am saying that all of my topic branches are based on
master, and if I were to rebase them (for example), I'd want to rebase
the whole thing.
If I were to "git pull", they'd also pull from master, which may or may
not be what you want (though with pull.rebase, perhaps). I don't
generally use "git pull" at all for my git.git workflow.
> > And then rebasing always happens on top of master (because "origin"
> > doesn't even have my topic branch at all). If I want to compare with
> > what I've pushed to my fork, I'd use "@{push}".
>
> Can you explain more about how your rebase chooses master instead of
> your same-named remote tracking branch? Maybe provide some examples of
> your rebase command and respective configuration (unless what you've
> already provided is sufficient). As for @{push}, I haven't used this
> before, so I'll dig in the docs and learn about it.
The default for "git rebase" (if you don't specify a base) is the
configured upstream, which in my case is origin/master. Most of my
rebasing is "rebase -i" to rewrite bits, so it automatically picks all
the commits on my topic branch.
Maybe it would help to set up a trivial example:
# just a helper to make dummy commits
commit() { echo "$1" >"$1" && git add "$1" && git commit -m "$1"; }
# some parent repo
git init parent
(cd parent && commit one)
# and imagine you have a public fork, too
git clone --bare parent myfork.git
# and then you have your local clone; in real life this is obviously
# the only one that would actually be on your machine, but this is a
# toy example
git clone parent local
cd local
# set up our triangular config
git remote add myfork ../myfork.git
git config remote.pushdefault myfork
git config push.default current
# now let's try a topic branch
git checkout -b topic origin
commit two
commit three
# config will show our topic based on origin/master:
# [branch "topic"]
# remote = origin
# merge = refs/heads/master
less .git/config
# this should default to all the commits in our topic (i.e., two, three)
git rebase -i
# let's imagine upstream makes more commits on master. We can "pull
# --rebase" to put our work on top
(cd ../parent && commit four)
git pull --rebase
# pushes go to the matching branch on myfork
git push
# if you want to see what you haven't pushed yet, you can use @{push}
commit five
git log @{push}..
# likewise, if you wanted to rebase only commits that you've been
# working on since your last push:
git rebase -i @{push}
# Now imagine "origin" picks up your branch...
(cd ../parent && git fetch ../myfork.git topic:topic)
# Depending on your project's workflow, you may want to consider that
# the new base for further development (and never rebase or rewrite
# any commits that origin has). You do that by re-pointing your
# @{upstream} config.
git fetch
git branch --set-upstream-to=origin/topic topic
# now a "rebase -i" would show only the commits origin doesn't have
# (five and six in this case)
commit six
git rebase -i
Hopefully that shows off some of the ways you can use the upstream and
push config in practice. Some people may not be as excited about the
"rebase" default as I am. I spend quite a lot of time at the end of a
series sifting through the commits via "rebase -i" and polishing them
up. I also test with "git rebase -x 'make test'".
-Peff
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Best "triangle" workflow setup?
2017-05-11 23:36 ` Jeff King
@ 2017-05-12 14:53 ` Robert Dailey
2017-05-13 6:43 ` Jeff King
0 siblings, 1 reply; 6+ messages in thread
From: Robert Dailey @ 2017-05-12 14:53 UTC (permalink / raw)
To: Jeff King; +Cc: Git
On Thu, May 11, 2017 at 6:36 PM, Jeff King <peff@peff.net> wrote:
> On Thu, May 11, 2017 at 04:23:03PM -0500, Robert Dailey wrote:
>
>> On Thu, May 11, 2017 at 3:17 PM, Jeff King <peff@peff.net> wrote:
>> > I think you want:
>> >
>> > [push]
>> > default = current
>> > [remote]
>> > pushDefault = myfork
>> >
>> > to make "git push" do what you want. And then generally have branches
>> > mark their counterparts on "origin" (which you can do either at creation
>> > time, or probably by using "git push -u origin my-topic" when you push
>> > them).
>>
>> So without the `pushDefault` setting, `current` will default to a
>> remote named `origin` if there is no tracking branch set, correct? So
>> `pushDefault` is effectively overriding this built-in default? In
>> addition, it seems like since this overrides `branch.name.remote`,
>> that this effectively makes the remote tracking branch *only* for
>> `pull`. Is this a correct understanding?
>
> Right. The general idea of a triangular workflow is that where you pull
> from is not the same as where you push to. We have branch.*.pushremote
> if you really wanted to do it on a per-branch basis, but in my
> experience you almost always want to use "myfork", because you can't
> push to "origin" in the first place. :)
>
>> > This is similar to what I do for my git.git workflow, though I usually
>> > have origin/master as the branch's upstream. I.e., I'd create them with:
>> >
>> > git checkout -b my-topic origin
>>
>> I'm looking through the `git checkout` and `git branch` documentation,
>> but I don't see any mention of it being valid to use a remote name as
>> the <start-point> parameter (you're using `origin` in the above
>> example). Am I misunderstanding? Did you mean origin/my-topic?
>
> Using "origin" there will resolve to "origin/HEAD", i.e., origin/master.
> So basically I am saying that all of my topic branches are based on
> master, and if I were to rebase them (for example), I'd want to rebase
> the whole thing.
>
> If I were to "git pull", they'd also pull from master, which may or may
> not be what you want (though with pull.rebase, perhaps). I don't
> generally use "git pull" at all for my git.git workflow.
Thanks, just curious, where in the git documentation is the "origin"
to "origin/HEAD" resolution documented? I checked the git-revisions
page but it doesn't seem to mention it there. Thanks for explaining
though.
Also is there a similar mechanism for "track same-named branch on
specified remote"? Something like "origin/."? I follow git-flow
development process, so topic branches on hotfix or release branches
will track origin/master (since origin/HEAD still points to master or
develop). But I want to track "origin/release/1.2.3" without typing
the full thing. Basically would be nice if there was a lazy shorthand
for it similar to the "origin/HEAD" example you gave.
>> > And then rebasing always happens on top of master (because "origin"
>> > doesn't even have my topic branch at all). If I want to compare with
>> > what I've pushed to my fork, I'd use "@{push}".
>>
>> Can you explain more about how your rebase chooses master instead of
>> your same-named remote tracking branch? Maybe provide some examples of
>> your rebase command and respective configuration (unless what you've
>> already provided is sufficient). As for @{push}, I haven't used this
>> before, so I'll dig in the docs and learn about it.
>
> The default for "git rebase" (if you don't specify a base) is the
> configured upstream, which in my case is origin/master. Most of my
> rebasing is "rebase -i" to rewrite bits, so it automatically picks all
> the commits on my topic branch.
>
> Maybe it would help to set up a trivial example:
>
> # just a helper to make dummy commits
> commit() { echo "$1" >"$1" && git add "$1" && git commit -m "$1"; }
>
> # some parent repo
> git init parent
> (cd parent && commit one)
>
> # and imagine you have a public fork, too
> git clone --bare parent myfork.git
>
> # and then you have your local clone; in real life this is obviously
> # the only one that would actually be on your machine, but this is a
> # toy example
> git clone parent local
> cd local
>
> # set up our triangular config
> git remote add myfork ../myfork.git
> git config remote.pushdefault myfork
> git config push.default current
>
> # now let's try a topic branch
> git checkout -b topic origin
> commit two
> commit three
>
> # config will show our topic based on origin/master:
> # [branch "topic"]
> # remote = origin
> # merge = refs/heads/master
> less .git/config
>
> # this should default to all the commits in our topic (i.e., two, three)
> git rebase -i
>
> # let's imagine upstream makes more commits on master. We can "pull
> # --rebase" to put our work on top
> (cd ../parent && commit four)
> git pull --rebase
>
> # pushes go to the matching branch on myfork
> git push
>
> # if you want to see what you haven't pushed yet, you can use @{push}
> commit five
> git log @{push}..
>
> # likewise, if you wanted to rebase only commits that you've been
> # working on since your last push:
> git rebase -i @{push}
>
> # Now imagine "origin" picks up your branch...
> (cd ../parent && git fetch ../myfork.git topic:topic)
>
> # Depending on your project's workflow, you may want to consider that
> # the new base for further development (and never rebase or rewrite
> # any commits that origin has). You do that by re-pointing your
> # @{upstream} config.
> git fetch
> git branch --set-upstream-to=origin/topic topic
>
> # now a "rebase -i" would show only the commits origin doesn't have
> # (five and six in this case)
> commit six
> git rebase -i
>
>
> Hopefully that shows off some of the ways you can use the upstream and
> push config in practice. Some people may not be as excited about the
> "rebase" default as I am. I spend quite a lot of time at the end of a
> series sifting through the commits via "rebase -i" and polishing them
> up. I also test with "git rebase -x 'make test'".
Yes this is extremely helpful. I also like to default to rebase for
everything. I have this in my global config:
[pull]
rebase = true
[branch]
autosetuprebase = always
(Although I think autosetuprebase isn't needed anymore since
pull.rebase is introduced, but I keep both just in case)
So to summarize:
* Pushing to fork only ever requires `git push`
* Pushing to origin requires at least `git push origin` (for same-named branch)
* Pulling from origin always uses remote tracking branch (set to
mainline to merge latest into topic branch (single developer) or set
to same-named branch for multiple developers)
Another improvement that it seems like I'll have is that I do not need
to specify the branch name for my first-time pushes of a branch like I
had to do when `push.default` was set to `simple`. Back then I had to
do:
$ git push -u origin HEAD
Now all I gotta do is:
$ git push
I like this much better!! Thanks a ton!
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Best "triangle" workflow setup?
2017-05-12 14:53 ` Robert Dailey
@ 2017-05-13 6:43 ` Jeff King
0 siblings, 0 replies; 6+ messages in thread
From: Jeff King @ 2017-05-13 6:43 UTC (permalink / raw)
To: Robert Dailey; +Cc: Git
On Fri, May 12, 2017 at 09:53:23AM -0500, Robert Dailey wrote:
> Thanks, just curious, where in the git documentation is the "origin"
> to "origin/HEAD" resolution documented? I checked the git-revisions
> page but it doesn't seem to mention it there. Thanks for explaining
> though.
In gitrevisions(7), the <refname> section, rule 6:
otherwise, refs/remotes/<refname>/HEAD if it exists.
And then the contents of origin/HEAD are discussed a bit in
git-remote(1), under set-head.
> Also is there a similar mechanism for "track same-named branch on
> specified remote"? Something like "origin/."? I follow git-flow
> development process, so topic branches on hotfix or release branches
> will track origin/master (since origin/HEAD still points to master or
> develop). But I want to track "origin/release/1.2.3" without typing
> the full thing. Basically would be nice if there was a lazy shorthand
> for it similar to the "origin/HEAD" example you gave.
No, I don't think there's a shorthand for "the same-named branch". But
there are two things that might help:
1. If you're always branching from release/1.2.3 instead of "master",
you can use "git remote set-head" to change it.
2. If you want a local branch "foo" to track refs/remotes/origin/foo
(which already exists) then the checkout-dwim should work for you:
$ git checkout foo
Branch foo set up to track remote branch foo from origin.
Switched to a new branch 'foo'
-Peff
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-05-13 6:43 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-11 19:41 Best "triangle" workflow setup? Robert Dailey
2017-05-11 20:17 ` Jeff King
2017-05-11 21:23 ` Robert Dailey
2017-05-11 23:36 ` Jeff King
2017-05-12 14:53 ` Robert Dailey
2017-05-13 6:43 ` Jeff King
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).