[packagers] Commit policy and git tutorial

Yury V. Zaytsev yury at shurup.com
Thu Apr 14 21:19:49 CEST 2011


So here I am to tell you about the new world order after the migration
to git. As Dag suggested, hopefully, I will take the relevant parts out
of it to put them into the wiki. The word to the users will be sent
later as I get to it.

Git is a distributed version control system. If you would like to
understand the basic concepts behind DVCS and how they have got there,
the I would recommend [1] as the best introduction that I've read. 

Otherwise, you can google up hundreds of introductions to your liking,
but the point of this e-mail is to spare your time searching & reading
and only tell what is relevant to our workflow (the advices are of
course based on my experience and can be discussed if someone comes up
with better ideas).

These notes are not intended to be a replacement for a git manual or
anything like that. If you'd like to become a pro with git, I highly
recommend you reading ProGit [2], a free book about git that is totally

Before we begin, remember that there is this cool functionality of
creating personal forks at GitHub. If you are uncomfortable with git,
feel free to fork the main repository to your account, clone it and try
all the crazy things you might come up with. This will not affect anyone
and in the end you will learn something new :-)

[1]: http://tom.preston-werner.com/2009/05/19/the-git-parable.html
[2]: http://progit.org/book/

Workflow and the commit policy

I suggest to establish the following workflow. A limited number of
reasonably trusted packagers (those who had access to the svn before for
the time being) have direct push access to the main repository. 

External contributors that didn't make it into the circle of trust yet
basically have to options:

a) If they use github, fork the repository, make changes, commit, push
and submit a pull request for us to review. 

Anyone with direct commit access may review and commit, but if you are
intending to take care of a particular request, please leave a comment
on github right there, so that other people wouldn't waste time
reviewing something that is already being taken care of.

b) If they don't, then they have to clone the repository, make changes
and send the result of "git diff" or commit and "git format-patch HEAD~"
to the mailing list. 

The only thing that should be completely banned would be the so called
non-fastforward pushes (git push -f), or pushes that overwrite once
published history. Otherwise, commit and push as you are comfortable.

Setting up git for the first time use

Before you start, please adjust the default settings right after you
installed git:

    $ git config --global user.name "Your X. Name"
    $ git config --global user.email "your at github.email"

Additionally, these are my favorites [1]:

    $ git config --global color.ui auto
    $ git config --global color.interactive auto

    $ git config --global alias.amend "commit --amend"
    $ git config --global alias.unstash "stash pop"
    $ git config --global alias.wdiff "diff --word-diff"

[1]: https://wincent.com/wiki/Git_quickstart

Typical tasks from the past translated into git speak

So, git is a highly sophisticated decentralized version control system.
This translates into a number of differences that you have to consider.

=== Cloning the repository

First and foremost, each and every git checkout contains the full
history of the project (in our case, I've got it compressed to ~35M). 

This also has a nice side effect of all operations which require access
to the history (log, diff, blame etc.) being instantaneous.

So instead of checking out a working copy as with svn, you *clone* the
repository to start working with it:

    $ git clone git at github.com:repoforge/rpms.git
        (clone via ssh, only if you are part of the team, r/w)

    $ git clone https://you@github.com/repoforge/rpms.git 
        (clone via https, anonymous or not, r/o or r/w)

    $ git clone git://github.com/repoforge/rpms.git 
        (clone via native protocol, anonymous, r/o)

To browse the history anytime use the graphical viewer, gitk:

    $ gitk

Alternatively, there is a console client called tig:

    $ tig

=== Keeping your clone up to date with the server

When using svn, you keep your working copy up to date by doing "svn up".
This fetches the updates from the server and implicitly tries to merge
them with your local changes if any. 

With git everything is explicit (this is what I like a lot about it).
You fetch the updates from the server using "git fetch" and merge them
with your changes with "git merge". There's a shortcut available which
we will discuss in a minute.

The thing is that when a merge occurs, even if the changes are not
conflicting (which will happen 99% of the time with us) or can be
resolved automatically, git records a merge, which makes the history
look like crap [1].

Luckily, there is a command that can fetch the changes from the server,
try to see if the conflict or not, and in the case if there is no
conflict or it can be resolved automatically, it will just roll your
changes on top of the lastest stuff from the repository:

    $ git pull --rebase

If there is a conflict, however, you will be asked to resolve it as
usual. After you have resolved the conflict and removed the conflict
markers, do git add and commit the affected files.

Of course, this flag is easy to forget (if so, git will do a
full-fledged merge instead as I described above), so in order to avoid
this, please make it the default for this repository [2]:

    $ git config branch.master.rebase true
    $ git config branch.autosetuprebase always

[1]: http://gitready.com/advanced/2009/02/11/pull-with-rebase.html
[2]: http://d.strelau.net/post/47338904/git-pull-rebase-by-default

=== Recording and publishing your changes

In line with what I have just said, in svn you would use "svn commit" to
record the changes in the current directory and send them to the server.

With git it's different, because it's more explicit (gives you access to
the so called staging area) and you have to take into account that many
git users work offline. 

So generally, the process is broken down into three steps:

 1. First, you need to add your changes to the staging area:

    $ git add foo.spec bar.patch

 2. Second, you need to commit your changes:

    $ git commit

 3. Third, you need to make your changes available to the others:

    $ git push

At this point, it could turn out that somebody has pushed already in
between and you need to rebase you changes first (as described above) to
make sure that there are no possible conflicts:

    $ git pull --rebase
        (or set it as the default)

    $ git push
        (now everything goes well)

There's a shortcut, if you want to commit all files that you have
changed (skip adding them to the staging area one by one):

    $ git commit -a

=== Miscellanea

To see the current state of the repository (which files have been
changed, removed and added):

    $ git status

To obtain the diff of you local uncommitted changes against the last
commit try:

    $ git diff

Sometimes not so nice things happen and you want to revert the changes
that you have made to a particular file.

This is different in git as compared to svn:

    $ git checkout path/file.ext

It could happen that you mess things up oh so badly. 

In the end, you want to reset your working copy (your local master
branch) to the state it was when it was last published on the common

    $ git reset --hard origin/master

Be *very* careful with this command!!!

This will destroy *all* your uncommitted local changes and even those
that you have already committed, but not pushed yet.

Integrating external contributions

By default, github suggests a little bit tedious way of merging external
contributions. This works well for a large project when multiple
conflicting changes are being made while the pull request is being
reviewed, but for us it will result into a lot of unnecessary overhead.

Therefore, I suggest the following:

1) If external contribution is incomplete and requires a lot of extra
work, do as github suggests

2) Small contributions, which don't need any changes, can be directly
imported into master, i.e.:

    $ git pull --rebase https://github.com/user/repoforge.git master

    $ gitk
        (check that everything looks alright)

    $ git push

Always be very cautious about what you are doing! If you are not sure,
just post to the list and hopefully someone will be able to help you.

Sincerely yours,
Yury V. Zaytsev

More information about the packagers mailing list