[Python-Dev] PEP: Collecting information about git

Guido van Rossum guido at python.org
Sat Sep 12 17:29:10 CEST 2015


I have only skimmed the first half but it looks really good.

On Sat, Sep 12, 2015 at 8:12 AM, Brett Cannon <brett at python.org> wrote:

> I have not had a chance to read Oleg's PEP, but the devguide has the
> reverse docs at https://docs.python.org/devguide/gitdevs.html so we have
> the VCS docs down pat. :)
>
> On Sat, Sep 12, 2015, 06:59 Oleg Broytman <phd at phdru.name> wrote:
>
>> PEP: XXX
>> Title: Collecting information about git
>> Version: $Revision$
>> Last-Modified: $Date$
>> Author: Oleg Broytman <phd at phdru.name>
>> Status: Draft
>> Type: Informational
>> Content-Type: text/x-rst
>> Created: 01-Jun-2015
>> Post-History: 12-Sep-2015
>>
>> Abstract
>> ========
>>
>> This Informational PEP collects information about git. There is, of
>> course, a lot of documentation for git, so the PEP concentrates on
>> more complex (and more related to Python development) issues,
>> scenarios and examples.
>>
>> The plan is to extend the PEP in the future collecting information
>> about equivalence of Mercurial and git scenarios to help migrating
>> Python development from Mercurial to git.
>>
>> The author of the PEP doesn't currently plan to write a Process PEP on
>> migration Python development from Mercurial to git.
>>
>>
>> Documentation
>> =============
>>
>> Git is accompanied with a lot of documentation, both online and
>> offline.
>>
>>
>> Documentation for starters
>> --------------------------
>>
>> Git Tutorial: `part 1
>> <https://www.kernel.org/pub/software/scm/git/docs/gittutorial.html>`_,
>> `part 2
>> <https://www.kernel.org/pub/software/scm/git/docs/gittutorial-2.html>`_.
>>
>> `Git User's manual
>> <https://www.kernel.org/pub/software/scm/git/docs/user-manual.html>`_.
>> `Everyday GIT With 20 Commands Or So
>> <https://www.kernel.org/pub/software/scm/git/docs/everyday.html>`_.
>> `Git workflows
>> <https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html>`_.
>>
>>
>> Advanced documentation
>> ----------------------
>>
>> `Git Magic
>> <http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html>`_,
>> with a number of translations.
>>
>> `Pro Git <https://git-scm.com/book>`_. The Book about git. Buy it at
>> Amazon or download in PDF, mobi, or ePub form. It has translations to
>> many different languages. Download Russian translation from `GArik
>> <https://github.com/GArik/progit/wiki>`_.
>>
>> `Git Wiki <https://git.wiki.kernel.org/index.php/Main_Page>`_.
>>
>>
>> Offline documentation
>> ---------------------
>>
>> Git has builtin help: run ``git help $TOPIC``. For example, run
>> ``git help git`` or ``git help help``.
>>
>>
>> Quick start
>> ===========
>>
>> Download and installation
>> -------------------------
>>
>> Unix users: `download and install using your package manager
>> <https://git-scm.com/download/linux>`_.
>>
>> Microsoft Windows: download `git-for-windows
>> <https://github.com/git-for-windows/git/releases>`_ or `msysGit
>> <https://github.com/msysgit/msysgit/releases>`_.
>>
>> MacOS X: use git installed with `XCode
>> <https://developer.apple.com/xcode/downloads/>`_ or download from
>> `MacPorts <https://www.macports.org/ports.php?by=name&substr=git>`_ or
>> `git-osx-installer
>> <http://sourceforge.net/projects/git-osx-installer/files/>`_ or
>> install git with `Homebrew <http://brew.sh/>`_: ``brew install git``.
>>
>> `git-cola <https://git-cola.github.io/index.html>`_ is a Git GUI
>> written in Python and GPL licensed. Linux, Windows, MacOS X.
>>
>> `TortoiseGit <https://tortoisegit.org/>`_ is a Windows Shell Interface
>> to Git based on TortoiseSVN; open source.
>>
>>
>> Initial configuration
>> ---------------------
>>
>> This simple code is often appears in documentation, but it is
>> important so let repeat it here. Git stores author and committer
>> names/emails in every commit, so configure your real name and
>> preferred email::
>>
>>     $ git config --global user.name "User Name"
>>     $ git config --global user.email user.name at example.org
>>
>>
>> Examples in this PEP
>> ====================
>>
>> Examples of git commands in this PEP use the following approach. It is
>> supposed that you, the user, works with a local repository named
>> ``python`` that has an upstream remote repo named ``origin``. Your
>> local repo has two branches ``v1`` and ``master``. For most examples
>> the currently checked out branch is ``master``. That is, it's assumed
>> you have done something like that::
>>
>>     $ git clone https://git.python.org/python.git
>>     $ cd python
>>     $ git branch v1 origin/v1
>>
>> The first command clones remote repository into local directory
>> `python``, creates a new local branch master, sets
>> remotes/origin/master as its upstream remote-tracking branch and
>> checks it out into the working directory.
>>
>> The last command creates a new local branch v1 and sets
>> remotes/origin/v1 as its upstream remote-tracking branch.
>>
>> The same result can be achieved with commands::
>>
>>     $ git clone -b v1 https://git.python.org/python.git
>>     $ cd python
>>     $ git checkout --track origin/master
>>
>> The last command creates a new local branch master, sets
>> remotes/origin/master as its upstream remote-tracking branch and
>> checks it out into the working directory.
>>
>>
>> Branches and branches
>> =====================
>>
>> Git terminology can be a bit misleading. Take, for example, the term
>> "branch". In git it has two meanings. A branch is a directed line of
>> commits (possibly with merges). And a branch is a label or a pointer
>> assigned to a line of commits. It is important to distinguish when you
>> talk about commits and when about their labels. Lines of commits are
>> by itself unnamed and are usually only lengthening and merging.
>> Labels, on the other hand, can be created, moved, renamed and deleted
>> freely.
>>
>>
>> Remote repositories and remote branches
>> =======================================
>>
>> Remote-tracking branches are branches (pointers to commits) in your
>> local repository. They are there for git (and for you) to remember
>> what branches and commits have been pulled from and pushed to what
>> remote repos (you can pull from and push to many remotes).
>> Remote-tracking branches live under ``remotes/$REMOTE`` namespaces,
>> e.g. ``remotes/origin/master``.
>>
>> To see the status of remote-tracking branches run::
>>
>>     $ git branch -rv
>>
>> To see local and remote-tracking branches (and tags) pointing to
>> commits::
>>
>>     $ git log --decorate
>>
>> You never do your own development on remote-tracking branches. You
>> create a local branch that has a remote branch as upstream and do
>> development on that local branch. On push git pushes commits to the
>> remote repo and updates remote-tracking branches, on pull git fetches
>> commits from the remote repo, updates remote-tracking branches and
>> fast-forwards, merges or rebases local branches.
>>
>> When you do an initial clone like this::
>>
>>     $ git clone -b v1 https://git.python.org/python.git
>>
>> git clones remote repository ``https://git.python.org/python.git``
>> <https://git.python.org/python.git> to
>> directory ``python``, creates a remote named ``origin``, creates
>> remote-tracking branches, creates a local branch ``v1``, configure it
>> to track upstream remotes/origin/v1 branch and checks out ``v1`` into
>> the working directory.
>>
>>
>> Updating local and remote-tracking branches
>> -------------------------------------------
>>
>> There is a major difference between
>>
>> ::
>>
>>     $ git fetch $REMOTE $BRANCH
>>
>> and
>>
>> ::
>>
>>     $ git fetch $REMOTE $BRANCH:$BRANCH
>>
>> The first command fetches commits from the named $BRANCH in the
>> $REMOTE repository that are not in your repository, updates
>> remote-tracking branch and leaves the id (the hash) of the head commit
>> in file .git/FETCH_HEAD.
>>
>> The second command fetches commits from the named $BRANCH in the
>> $REMOTE repository that are not in your repository and updates both
>> the local branch $BRANCH and its upstream remote-tracking branch. But
>> it refuses to update branches in case of non-fast-forward. And it
>> refuses to update the current branch (currently checked out branch,
>> where HEAD is pointing to).
>>
>> The first command is used internally by ``git pull``.
>>
>> ::
>>
>>     $ git pull $REMOTE $BRANCH
>>
>> is equivalent to
>>
>> ::
>>
>>     $ git fetch $REMOTE $BRANCH
>>     $ git merge FETCH_HEAD
>>
>> Certainly, $BRANCH in that case should be your current branch. If you
>> want to merge a different branch into your current branch first update
>> that non-current branch and then merge::
>>
>>     $ git fetch origin v1:v1  # Update v1
>>     $ git pull --rebase origin master  # Update the current branch master
>>                                        # using rebase instead of merge
>>     $ git merge v1
>>
>> If you have not yet pushed commits on ``v1``, though, the scenario has
>> to become a bit more complex. Git refuses to update
>> non-fast-forwardable branch, and you don't want to do force-pull
>> because that would remove your non-pushed commits and you would need
>> to recover. So you want to rebase ``v1`` but you cannot rebase
>> non-current branch. Hence, checkout ``v1`` and rebase it before
>> merging::
>>
>>     $ git checkout v1
>>     $ git pull --rebase origin v1
>>     $ git checkout master
>>     $ git pull --rebase origin master
>>     $ git merge v1
>>
>> It is possible to configure git to make it fetch/pull a few branches
>> or all branches at once, so you can simply run
>>
>> ::
>>
>>     $ git pull origin
>>
>> or even
>>
>> ::
>>
>>     $ git pull
>>
>> Default remote repository for fetching/pulling is ``origin``. Default
>> set of references to fetch is calculated using matching algorithm: git
>> fetches all branches having the same name on both ends.
>>
>>
>> Push
>> ''''
>>
>> Pushing is a bit simpler. There is only one command ``push``. When you
>> run
>>
>> ::
>>
>>     $ git push origin v1 master
>>
>> git pushes local v1 to remote v1 and local master to remote master.
>> The same as::
>>
>>     $ git push origin v1:v1 master:master
>>
>> Git pushes commits to the remote repo and updates remote-tracking
>> branches. Git refuses to push commits that aren't fast-forwardable.
>> You can force-push anyway, but please remember - you can force-push to
>> your own repositories but don't force-push to public or shared repos.
>> If you find git refuses to push commits that aren't fast-forwardable,
>> better fetch and merge commits from the remote repo (or rebase your
>> commits on top of the fetched commits), then push. Only force-push if
>> you know what you do and why you do it. See the section `Commit
>> editing and caveats`_ below.
>>
>> It is possible to configure git to make it push a few branches or all
>> branches at once, so you can simply run
>>
>> ::
>>
>>     $ git push origin
>>
>> or even
>>
>> ::
>>
>>     $ git push
>>
>> Default remote repository for pushing is ``origin``. Default set of
>> references to push in git before 2.0 is calculated using matching
>> algorithm: git pushes all branches having the same name on both ends.
>> Default set of references to push in git 2.0+ is calculated using
>> simple algorithm: git pushes the current branch back to its
>> @{upstream}.
>>
>> To configure git before 2.0 to the new behaviour run::
>>
>> $ git config push.default simple
>>
>> To configure git 2.0+ to the old behaviour run::
>>
>> $ git config push.default matching
>>
>> Git doesn't allow to push a branch if it's the current branch in the
>> remote non-bare repository: git refuses to update remote working
>> directory. You really should push only to bare repositories. For
>> non-bare repositories git prefers pull-based workflow.
>>
>> When you want to deploy code on a remote host and can only use push
>> (because your workstation is behind a firewall and you cannot pull
>> from it) you do that in two steps using two repositories: you push
>> from the workstation to a bare repo on the remote host, ssh to the
>> remote host and pull from the bare repo to a non-bare deployment repo.
>>
>> That changed in git 2.3, but see `the blog post
>> <https://github.com/blog/1957-git-2-3-has-been-released#push-to-deploy>`_
>> for caveats; in 2.4 the push-to-deploy feature was `further improved
>> <
>> https://github.com/blog/1994-git-2-4-atomic-pushes-push-to-deploy-and-more#push-to-deploy-improvements
>> >`_.
>>
>>
>> Tags
>> ''''
>>
>> Git automatically fetches tags that point to commits being fetched
>> during fetch/pull. To fetch all tags (and commits they point to) run
>> ``git fetch --tags origin``. To fetch some specific tags fetch them
>> explicitly::
>>
>>     $ git fetch origin tag $TAG1 tag $TAG2...
>>
>> For example::
>>
>>     $ git fetch origin tag 1.4.2
>>     $ git fetch origin v1:v1 tag 2.1.7
>>
>> Git doesn't automatically pushes tags. That allows you to have private
>> tags. To push tags list them explicitly::
>>
>>     $ git push origin tag 1.4.2
>>     $ git push origin v1 master tag 2.1.7
>>
>> Or push all tags at once::
>>
>>     $ git push --tags origin
>>
>> Don't move tags with ``git tag -f`` or remove tags with ``git tag -d``
>> after they have been published.
>>
>>
>> Private information
>> '''''''''''''''''''
>>
>> When cloning/fetching/pulling/pushing git copies only database objects
>> (commits, trees, files and tags) and symbolic references (branches and
>> lightweight tags). Everything else is private to the repository and
>> never cloned, updated or pushed. It's your config, your hooks, your
>> private exclude file.
>>
>> If you want to distribute hooks, copy them to the working tree, add,
>> commit, push and instruct the team to update and install the hooks
>> manually.
>>
>>
>> Commit editing and caveats
>> ==========================
>>
>> A warning not to edit published (pushed) commits also appears in
>> documentation but it's repeated here anyway as it's very important.
>>
>> It is possible to recover from a forced push but it's PITA for the
>> entire team. Please avoid it.
>>
>> To see what commits have not been published yet compare the head of the
>> branch with its upstream remote-tracking branch::
>>
>>     $ git log origin/master..  # from origin/master to HEAD (of master)
>>     $ git log origin/v1..v1  # from origin/v1 to the head of v1
>>
>> For every branch that has an upstream remote-tracking branch git
>> maintains an alias @{upstream} (short version @{u}), so the commands
>> above can be given as::
>>
>>     $ git log @{u}..
>>     $ git log v1@{u}..v1
>>
>> To see the status of all branches::
>>
>>     $ git branch -avv
>>
>> To compare the status of local branches with a remote repo::
>>
>>     $ git remote show origin
>>
>> Read `how to recover from upstream rebase
>> <https://git-scm.com/docs/git-rebase#_recovering_from_upstream_rebase>`_.
>> It is in ``git help rebase``.
>>
>> On the other hand don't be too afraid about commit editing. You can
>> safely edit, reorder, remove, combine and split commits that haven't
>> been pushed yet. You can even push commits to your own (backup) repo,
>> edit them later and force-push edited commits to replace what have
>> already been pushed. Not a problem until commits are in a public
>> or shared repository.
>>
>>
>> Undo
>> ====
>>
>> Whatever you do, don't panic. Almost anything in git can be undone.
>>
>>
>> git checkout: restore file's content
>> ------------------------------------
>>
>> ``git checkout``, for example, can be used to restore the content of
>> file(s) to that one of a commit. Like this::
>>
>>     git checkout HEAD~ README
>>
>> The commands restores the contents of README file to the last but one
>> commit in the current branch. By default the commit ID is simply HEAD;
>> i.e. ``git checkout README`` restores README to the latest commit.
>>
>> (Do not use ``git checkout`` to view a content of a file in a commit,
>> use ``git cat-file -p``; e.g. ``git cat-file -p HEAD~:path/to/README``).
>>
>>
>> git reset: remove (non-pushed) commits
>> --------------------------------------
>>
>> ``git reset`` moves the head of the current branch. The head can be
>> moved to point to any commit but it's often used to remove a commit or
>> a few (preferably, non-pushed ones) from the top of the branch - that
>> is, to move the branch backward in order to undo a few (non-pushed)
>> commits.
>>
>> ``git reset`` has three modes of operation - soft, hard and mixed.
>> Default is mixed. ProGit `explains
>> <https://git-scm.com/book/en/Git-Tools-Reset-Demystified>`_ the
>> difference very clearly. Bare repositories don't have indices or
>> working trees so in a bare repo only soft reset is possible.
>>
>>
>> Unstaging
>> '''''''''
>>
>> Mixed mode reset with a path or paths can be used to unstage changes -
>> that is, to remove from index changes added with ``git add`` for
>> committing. See `The Book
>> <https://git-scm.com/book/en/Git-Basics-Undoing-Things>`_ for details
>> about unstaging and other undo tricks.
>>
>>
>> git reflog: reference log
>> -------------------------
>>
>> Removing commits with ``git reset`` or moving the head of a branch
>> sounds dangerous and it is. But there is a way to undo: another
>> reset back to the original commit. Git doesn't remove commits
>> immediately; unreferenced commits (in git terminology they are called
>> "dangling commits") stay in the database for some time (default is two
>> weeks) so you can reset back to it or create a new branch pointing to
>> the original commit.
>>
>> For every move of a branch's head - with ``git commit``, ``git
>> checkout``, ``git fetch``, ``git pull``, ``git rebase``, ``git reset``
>> and so on - git stores a reference log (reflog for short). For every
>> move git stores where the head was. Command ``git reflog`` can be used
>> to view (and manipulate) the log.
>>
>> In addition to the moves of the head of every branch git stores the
>> moves of the HEAD - a symbolic reference that (usually) names the
>> current branch. HEAD is changed with ``git checkout $BRANCH``.
>>
>> By default ``git reflog`` shows the moves of the HEAD, i.e. the
>> command is equivalent to ``git reflog HEAD``. To show the moves of the
>> head of a branch use the command ``git reflog $BRANCH``.
>>
>> So to undo a ``git reset`` lookup the original commit in ``git
>> reflog``, verify it with ``git show`` or ``git log`` and run ``git
>> reset $COMMIT_ID``. Git stores the move of the branch's head in
>> reflog, so you can undo that undo later again.
>>
>> In a more complex situation you'd want to move some commits along with
>> resetting the head of the branch. Cherry-pick them to the new branch.
>> For example, if you want to reset the branch ``master`` back to the
>> original commit but preserve two commits created in the current branch
>> do something like::
>>
>>     $ git branch save-master # create a new branch saving master
>>     $ git reflog # find the original place of master
>>     $ git reset $COMMIT_ID
>>     $ git cherry-pick save-master~ save-master
>>     $ git branch -D save-master # remove temporary branch
>>
>>
>> git revert: revert a commit
>> ---------------------------
>>
>> ``git revert`` reverts a commit or commits, that is, it creates a new
>> commit or commits that revert(s) the effects of the given commits.
>> It's the only way to undo published commits (``git commit --amend``,
>> ``git rebase`` and ``git reset`` change the branch in
>> non-fast-forwardable ways so they should only be used for non-pushed
>> commits.)
>>
>> There is a problem with reverting a merge commit. ``git revert`` can
>> undo the code created by the merge commit but it cannot undo the fact
>> of merge. See the discussion `How to revert a faulty merge
>> <
>> https://www.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.html
>> >`_.
>>
>>
>> One thing that cannot be undone
>> -------------------------------
>>
>> Whatever you undo, there is one thing that cannot be undone -
>> overwritten uncommitted changes. Uncommitted changes don't belong to
>> git so git cannot help preserving them.
>>
>> Most of the time git warns you when you're going to execute a command
>> that overwrites uncommitted changes. Git doesn't allow you to switch
>> branches with ``git checkout``. It stops you when you're going to
>> rebase with non-clean working tree. It refuses to pull new commits
>> over non-committed files.
>>
>> But there are commands that do exactly that - overwrite files in the
>> working tree. Commands like ``git checkout $PATHs`` or ``git reset
>> --hard`` silently overwrite files including your uncommitted changes.
>>
>> With that in mind you can understand the stance "commit early, commit
>> often". Commit as often as possible. Commit on every save in your
>> editor or IDE. You can edit your commits before pushing - edit commit
>> messages, change commits, reorder, combine, split, remove. But save
>> your changes in git database, either commit changes or at least stash
>> them with ``git stash``.
>>
>>
>> Merge or rebase?
>> ================
>>
>> Internet is full of heated discussions on the topic: "merge or
>> rebase?" Most of them are meaningless. When a DVCS is being used in a
>> big team with a big and complex project with many branches there is
>> simply no way to avoid merges. So the question's diminished to
>> "whether to use rebase, and if yes - when to use rebase?" Considering
>> that it is very much recommended not to rebase published commits the
>> question's diminished even further: "whether to use rebase on
>> non-pushed commits?"
>>
>> That small question is for the team to decide. The author of the PEP
>> recommends to use rebase when pulling, i.e. always do ``git pull
>> --rebase`` or even configure automatic setup of rebase for every new
>> branch::
>>
>>     $ git config branch.autosetuprebase always
>>
>> and configure rebase for existing branches::
>>
>>     $ git config branch.$NAME.rebase true
>>
>> For example::
>>
>>     $ git config branch.v1.rebase true
>>     $ git config branch.master.rebase true
>>
>> After that ``git pull origin master`` becomes equivalent to ``git pull
>> --rebase origin master``.
>>
>> It is recommended to create new commits in a separate feature or topic
>> branch while using rebase to update the mainline branch. When the
>> topic branch is ready merge it into mainline. To avoid a tedious task
>> of resolving large number of conflicts at once you can merge the topic
>> branch to the mainline from time to time and switch back to the topic
>> branch to continue working on it. The entire workflow would be
>> something like::
>>
>>     $ git checkout -b issue-42  # create a new issue branch and switch to
>> it
>>         ...edit/test/commit...
>>     $ git checkout master
>>     $ git pull --rebase origin master  # update master from the upstream
>>     $ git merge issue-42
>>     $ git branch -d issue-42  # delete the topic branch
>>     $ git push origin master
>>
>> When the topic branch is deleted only the label is removed, commits
>> are stayed in the database, they are now merged into master::
>>
>>     o--o--o--o--o--M--< master - the mainline branch
>>         \         /
>>          --*--*--*             - the topic branch, now unnamed
>>
>> The topic branch is deleted to avoid cluttering branch namespace with
>> small topic branches. Information on what issue was fixed or what
>> feature was implemented should be in the commit messages.
>>
>>
>> Null-merges
>> ===========
>>
>> Git has a builtin merge strategy for what Python core developers call
>> "null-merge"::
>>
>>     $ git merge -s ours v1  # null-merge v1 into master
>>
>>
>> Advanced configuration
>> ======================
>>
>> Line endings
>> ------------
>>
>> Git has builtin mechanisms to handle line endings between platforms
>> with different end-of-line styles. To allow git to do CRLF conversion
>> assign ``text`` attribute to files using `.gitattributes
>> <https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html>`_.
>> For files that have to have specific line endings assign ``eol``
>> attribute. For binary files the attribute is, naturally, ``binary``.
>>
>> For example::
>>
>>     $ cat .gitattributes
>>     *.py text
>>     *.txt text
>>     *.png binary
>>     /readme.txt eol=CRLF
>>
>> To check what attributes git uses for files use ``git check-attr``
>> command. For example::
>>
>> $ git check-attr -a -- \*.py
>>
>>
>> Advanced topics
>> ===============
>>
>> Staging area
>> ------------
>>
>> Staging area aka index aka cache is a distinguishing feature of git.
>> Staging area is where git collects patches before committing them.
>> Separation between collecting patches and commit phases provides a
>> very useful feature of git: you can review collected patches before
>> commit and even edit them - remove some hunks, add new hunks and
>> review again.
>>
>> To add files to the index use ``git add``. Collecting patches before
>> committing means you need to do that for every change, not only to add
>> new (untracked) files. To simplify committing in case you just want to
>> commit everything without reviewing run ``git commit --all`` (or just
>> ``-a``) - the command adds every changed tracked file to the index and
>> then commit. To commit a file or files regardless of patches collected
>> in the index run ``git commit [--only|-o] -- $FILE...``.
>>
>> To add hunks of patches to the index use ``git add --patch`` (or just
>> ``-p``). To remove collected files from the index use ``git reset HEAD
>> -- $FILE...`` To add/inspect/remove collected hunks use ``git add
>> --interactive`` (``-i``).
>>
>> To see the diff between the index and the last commit (i.e., collected
>> patches) use ``git diff --cached``. To see the diff between the
>> working tree and the index (i.e., uncollected patches) use just ``git
>> diff``. To see the diff between the working tree and the last commit
>> (i.e., both collected and uncollected patches) run ``git diff HEAD``.
>>
>> See `WhatIsTheIndex
>> <https://git.wiki.kernel.org/index.php/WhatIsTheIndex>`_ and
>> `IndexCommandQuickref
>> <https://git.wiki.kernel.org/index.php/IndexCommandQuickref>`_ in Git
>> Wiki.
>>
>>
>> ReReRe
>> ======
>>
>> Rerere is a mechanism that helps to resolve repeated merge conflicts.
>> The most frequent source of recurring merge conflicts are topic
>> branches that are merged into mainline and then the merge commits are
>> removed; that's often performed to test the topic branches and train
>> rerere; merge commits are removed to have clean linear history and
>> finish the topic branch with only one last merge commit.
>>
>> Rerere works by remembering the states of tree before and after a
>> successful commit. That way rerere can automatically resolve conflicts
>> if they appear in the same files.
>>
>> Rerere can be used manually with ``git rerere`` command but most often
>> it's used automatically. Enable rerere with these commands in a
>> working tree::
>>
>>     $ git config rerere.enabled true
>>     $ git config rerere.autoupdate true
>>
>> You don't need to turn rerere on globally - you don't want rerere in
>> bare repositories or single-branche repositories; you only need rerere
>> in repos where you often perform merges and resolve merge conflicts.
>>
>> See `Rerere <https://git-scm.com/book/en/Git-Tools-Rerere>`_ in The
>> Book.
>>
>>
>> Database maintenance
>> ====================
>>
>> Git object database and other files/directories under ``.git`` require
>> periodic maintenance and cleanup. For example, commit editing left
>> unreferenced objects (dangling objects, in git terminology) and these
>> objects should be pruned to avoid collecting cruft in the DB. The
>> command ``git gc`` is used for maintenance. Git automatically runs
>> ``git gc --auto`` as a part of some commands to do quick maintenance.
>> Users are recommended to run ``git gc --aggressive`` from time to
>> time; ``git help gc`` recommends to run it  every few hundred
>> changesets; for more intensive projects it should be something like
>> once a week and less frequently (biweekly or monthly) for lesser
>> active projects.
>>
>> ``git gc --aggressive`` not only removes dangling objects, it also
>> repacks object database into indexed and better optimized pack(s); it
>> also packs symbolic references (branches and tags). Another way to do
>> it is to run ``git repack``.
>>
>> There is a well-known `message
>> <https://gcc.gnu.org/ml/gcc/2007-12/msg00165.html>`_ from Linus
>> Torvalds regarding "stupidity" of ``git gc --aggressive``. The message
>> can safely be ignored now. It is old and outdated, ``git gc
>> --aggressive`` became much better since that time.
>>
>> For those who still prefer ``git repack`` over ``git gc --aggressive``
>> the recommended parameters are ``git repack -a -d -f --depth=20
>> --window=250``. See `this detailed experiment
>> <http://vcscompare.blogspot.ru/2008/06/git-repack-parameters.html>`_
>> for explanation of the effects of these parameters.
>>
>> From time to time run ``git fsck [--strict]`` to verify integrity of
>> the database. ``git fsck`` may produce a list of dangling objects;
>> that's not an error, just a reminder to perform regular maintenance.
>>
>>
>> Tips and tricks
>> ===============
>>
>> Command-line options and arguments
>> ----------------------------------
>>
>> `git help cli
>> <https://www.kernel.org/pub/software/scm/git/docs/gitcli.html>`_
>> recommends not to combine short options/flags. Most of the times
>> combining works: ``git commit -av`` works perfectly, but there are
>> situations when it doesn't. E.g., ``git log -p -5`` cannot be combined
>> as ``git log -p5``.
>>
>> Some options have arguments, some even have default arguments. In that
>> case the argument for such option must be spelled in a sticky way:
>> ``-Oarg``, never ``-O arg`` because for an option that has a default
>> argument the latter means "use default value for option ``-O`` and
>> pass ``arg`` further to the option parser". For example, ``git grep``
>> has an option ``-O`` that passes a list of names of the found files to
>> a program; default program for ``-O`` is a pager (usually ``less``),
>> but you can use your editor::
>>
>>     $ git grep -Ovim # but not -O vim
>>
>> BTW, if git is instructed to use ``less`` as the pager (i.e., if pager
>> is not configured in git at all it uses ``less`` by default, or if it
>> gets ``less`` from GIT_PAGER or PAGER environment variables, or if it
>> was configured with ``git config --global core.pager less``, or
>> ``less`` is used in the command ``git grep -Oless``) ``git grep``
>> passes ``+/$pattern`` option to ``less`` which is quite convenient.
>> Unfortunately, ``git grep`` doesn't pass the pattern if the pager is
>> not exactly ``less``, even if it's ``less`` with parameters (something
>> like ``git config --global core.pager less -FRSXgimq``); fortunately,
>> ``git grep -Oless`` always passes the pattern.
>>
>>
>> bash/zsh completion
>> -------------------
>>
>> It's a bit hard to type ``git rebase --interactive --preserve-merges
>> HEAD~5`` manually even for those who are happy to use command-line,
>> and this is where shell completion is of great help. Bash/zsh come
>> with programmable completion, often automatically installed and
>> enabled, so if you have bash/zsh and git installed, chances are you
>> are already done - just go and use it at the command-line.
>>
>> If you don't have necessary bits installed, install and enable
>> bash_completion package. If you want to upgrade your git completion to
>> the latest and greatest download necessary file from `git contrib
>> <https://git.kernel.org/cgit/git/git.git/tree/contrib/completion>`_.
>>
>> Git-for-windows comes with git-bash for which bash completion is
>> installed and enabled.
>>
>>
>> bash/zsh prompt
>> ---------------
>>
>> For command-line lovers shell prompt can carry a lot of useful
>> information. To include git information in the prompt use
>> `git-prompt.sh
>> <
>> https://git.kernel.org/cgit/git/git.git/tree/contrib/completion/git-prompt.sh
>> >`_.
>> Read the detailed instructions in the file.
>>
>> Search the Net for "git prompt" to find other prompt variants.
>>
>>
>> git on server
>> =============
>>
>> The simplest way to publish a repository or a group of repositories is
>> ``git daemon``. The daemon provides anonymous access, by default it is
>> read-only. The repositories are accessible by git protocol (git://
>> URLs). Write access can be enabled but the protocol lacks any
>> authentication means, so it should be enabled only within a trusted
>> LAN. See ``git help daemon`` for details.
>>
>> Git over ssh provides authentication and repo-level authorisation as
>> repositories can be made user- or group-writeable (see parameter
>> ``core.sharedRepository`` in ``git help config``). If that's too
>> permissive or too restrictive for some project's needs there is a
>> wrapper `gitolite <http://gitolite.com/gitolite/index.html>`_ that can
>> be configured to allow access with great granularity; gitolite is
>> written in Perl and has a lot of documentation.
>>
>> Web interface to browse repositories can be created using `gitweb
>> <https://git.kernel.org/cgit/git/git.git/tree/gitweb>`_ or `cgit
>> <http://git.zx2c4.com/cgit/about/>`_. Both are CGI scripts (written in
>> Perl and C). In addition to web interface both provide read-only dumb
>> http access for git (http(s):// URLs).
>>
>> There are also more advanced web-based development environments that
>> include ability to manage users, groups and projects; private,
>> group-accessible and public repositories; they often include issue
>> trackers, wiki pages, pull requests and other tools for development
>> and communication. Among these environments are `Kallithea
>> <https://kallithea-scm.org/>`_ and `pagure <https://pagure.io/>`_,
>> both are written in Python; pagure was written by Fedora developers
>> and is being used to develop some Fedora projects. `Gogs
>> <http://gogs.io/>`_ is written in Go; there is a fork `Gitea
>> <http://gitea.io/>`_.
>>
>> And last but not least, `Gitlab <https://about.gitlab.com/>`_. It's
>> perhaps the most advanced web-based development environment for git.
>> Written in Ruby, community edition is free and open source (MIT
>> license).
>>
>>
>> From Mercurial to git
>> =====================
>>
>> There are many tools to convert Mercurial repositories to git. The
>> most famous are, probably, `hg-git <https://hg-git.github.io/>`_ and
>> `fast-export <http://repo.or.cz/w/fast-export.git>`_ (many years ago
>> it was known under the name ``hg2git``).
>>
>> But a better tool, perhaps the best, is `git-remote-hg
>> <https://github.com/felipec/git-remote-hg>`_. It provides transparent
>> bidirectional (pull and push) access to Mercurial repositories from
>> git. Its author wrote a `comparison of alternatives
>> <
>> https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives
>> >`_
>> that seems to be mostly objective.
>>
>> To use git-remote-hg, install or clone it, add to your PATH (or copy
>> script ``git-remote-hg`` to a directory that's already in PATH) and
>> prepend ``hg::`` to Mercurial URLs. For example::
>>
>>     $ git clone https://github.com/felipec/git-remote-hg.git
>>     $ PATH=$PATH:"`pwd`"/git-remote-hg
>>     $ git clone hg::https://hg.python.org/peps/ PEPs
>>
>> To work with the repository just use regular git commands including
>> ``git fetch/pull/push``.
>>
>> To start converting your Mercurial habits to git see the page
>> `Mercurial for Git users
>> <https://mercurial.selenic.com/wiki/GitConcepts>`_ at Mercurial wiki.
>> At the second half of the page there is a table that lists
>> corresponding Mercurial and git commands. Should work perfectly in
>> both directions.
>>
>>
>> Copyright
>> =========
>>
>> This document has been placed in the public domain.
>>
>>
>>
>> ..
>>    Local Variables:
>>    mode: indented-text
>>    indent-tabs-mode: nil
>>    sentence-end-double-space: t
>>    fill-column: 70
>>    coding: utf-8
>>    End:
>>    vim: set fenc=us-ascii tw=70 :
>> _______________________________________________
>> Python-Dev mailing list
>> Python-Dev at python.org
>> https://mail.python.org/mailman/listinfo/python-dev
>> Unsubscribe:
>> https://mail.python.org/mailman/options/python-dev/brett%40python.org
>>
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/guido%40python.org
>
>


-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20150912/19c9ba08/attachment-0001.html>


More information about the Python-Dev mailing list