On Thu, May 11, 2017 at 04:23:03PM -0500, Robert Dailey wrote:

> On Thu, May 11, 2017 at 3:17 PM, Jeff King <p...@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

Reply via email to