On Oct 31, 2007, at 10:31 PM, Junio C Hamano wrote:
Steffen Prohaska <prohaska@xxxxxx> writes:
You forgot a lot more important part. Pushing into publishing
repositories. And the discussion is about git-push command.
Exactly, here are two examples:
If you push only to publishing repositories that are read
only by others, you'll never encounter the problem that
10/10 tried to solve. The publishing repository is never
changed by others. You are the only one who pushes to this
repository. Therefore the remote never advances unexpectedly.
Wrong.
People can and do work from more than one private repositories
(I do). In a sense, that is sharing the repository with
oneself.
I do, too. But as long as I do not forget what I've done, the
branches do not advance _unexpectedly_. I am in full control.
I may do an emergency patch to fix breakage on 'maint' (and
'maint' only) from a location that is not my primary development
box and push the fix out. I fully expect that the push will
push out 'maint' and expect the other branches such as 'master'
on the remote side to stay the same, as I haven't touched
'master' on that box for quite a while and it is now stale. In
that situation, I _want_ the "git push" itself to report failure
to notify me that it did not push what _I_ asked it to push out,
so that I can be reminded that I'd better do "git push $remote
maint" the next time. In the meantime, even though it reports
a failure, 'master' on the remote side is _not_ updated, so the
behaviour is still _safe_.
You're right it is safe, but it may be confusing.
Another difference is the way changes are integrated. In
a workflow without shared repositories, only pull is used
for integration, while push in only used for publishing the
changes.
Wrong. push is a mirror of fetch and does not do _any_
integration. It is just a safe (because it insists on
fast-forward) propagation mechanism. Your integration still
happens with pull (actually, shared repository people seem to
prefer "fetch + rebase" over "pull" which is "fetch + merge").
Right; but you can't push without doing the integration. If you
have new changes on the remote side you _must_ pull before
you can push. You're forced to do the integration immediately.
Your main objective was to push, but the shared workflow forces
you to do the integration _now_ (by using pull). In a pull-only
workflow, you can just push and defere the integration for later.
Some people claim fetch + rebase is superior to fetch + merge.
The only point I can see is that fetch + rebase gives a linear
history without loops, which is nicer to visualize. I recently
asked on the list if there are any benefits of fetch + rebase
over fetch + merge, besides a nicer visualization. I didn't
receive many interesting comments. One comment explained
that rebase can shift the merge conflict resolution from
the maintainer (merge) to the original author (rebase). But
this is not very interesting in a shared workflow, because
the author must resolve conflicts in any case before he can
push. It doesn't matter much if he uses merge or rebase to
do so.
I evaluated if teaching people fetch + rebase before teaching
fetch + merge is a good idea. Therefore I tested some scenarios
with people who are new to git. The result is that there are
too many situations where fetch + rebase might be confusing.
I abandoned my idea.
I decided that fetch + merge is _easier_. It works in all
situations, it's easier to explain, it's better supported
(automerge), it can be used to work on shared topic branches.
Definitely fetch + merge is the first workflow you should
learn. At the moment I'm not anymore interested in the fetch +
rebase approach.
This is different if you work with a shared repository. Bob
checks out the shared branch foo to his local branch bar and
later he needs to push bar back to the shared branch foo. Bob
needs to push changes from his local branch bar to the branch
foo in the remote repository, a branch with a different name.
This need does not emerge when working with two publishing
repositories, as described above.
So you do "git push $remote bar:foo". If you do that regulary,
there are configuration mechanisms to help you reduce your
keyboard wear. What's the problem?
Too complex and not flexible enough.
The configuration is in the remote section. Therefore I can
tell git what to do only on a per-branch basis. What do you
think about my recent proposal to add branch.$name.push?
And I want to avoid that people need to learn about the details
of the configuration mechanism on the first time they use git.
I am searching for a solution that just works for them. They
currently use CVS. I'll give them a detailed getting started
document for git. The workflow described should be as simple as
possible, but safe and reliable. No confusing error messages
should appear. Only a few commands should be needed to
contribute to a shared branch. The workflow described should
use git in a sane way that provides opportunities to use more
of its power later.
So here is what I'd like to have.
git clone ssh://server/git/project.git project
[ On Windows the hassel already starts because it actually is
git clone -n ssh://sever/git/project.git project
git config core.autocrlf true
And here's the next point. git config doesn't validate the
variable. It accepts _any_ variable. If you have a typo
you go without autocrlf. ... but this is a different story. ]
cd project
git checkout -b devel origin/devel
# work, commit, work, commit
git push # maybe git pull first, but git would tell you
The last command, git push, can already cause trouble. git
automatically created a local master and the remote master
may have advanced, so git push would complain with an error.
Currently the correct command would be
"git push origin devel".
An alternative scenario is that you want to start work that
will not be ready right away. So you start a topic branch
git checkout -b topic origin/devel
# work, commit, some time passes, work, commit
git pull # integrate changes from devel
# work, commit
git pull
git push # this one should push to origin/devel
In scenario three you planned to finish your work right away
but the problem turned out to be harder. Here, the following
would be nice
git checkout -b devel origin/devel
# work, commit, hmm... much harder ...
git branch -m devel dolater
# do something else
git checkout dolater
# finish work
git pull # integrate with other work on devel
git push # push back to shared branch
Another question is what to do with a local branch after
you finished work. We recently had the
"Re: best git practices, was Re: Git User's Survey 2007
unfinished summary continued" aka the 200-local-branches
discussion.
There were different suggestions what to do. A reasonable
suggestion was to delete the local branch after you're done.
This clearly distinguishes between remote branches (which are
mirrored as a remote tracking branch) and local branches. Local
branches are _your_ branches while the remote branches contain
the shared work. If you're done with your local work, delete
your local branch. So maybe you should do
git checkout origin/devel
git branch -d devel
Now you're on a detached branch that points to origin/work.
But how to do you get new changes from others? git pull would
not work and git fetch neither.
Independently of what the best practice is, leaving the local
work branch there shouldn't do any harm because I'm sure that
some devs will forget to clean up, independently of what I tell
them.
Steffen
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html