On Thu, May 11, 2017 at 6:36 PM, Jeff King <peff@xxxxxxxx> 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@xxxxxxxx> 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!