2015-09-14 21:21:40 -04:00
|
|
|
|
PEP: 103
|
2015-09-14 18:12:42 -04:00
|
|
|
|
Title: Collecting information about git
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Oleg Broytman <phd@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/giteveryday.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>`_.
|
|
|
|
|
|
2016-01-13 15:36:39 -05:00
|
|
|
|
`Git Buch <http://gitbu.ch/index.html>`_ (German).
|
|
|
|
|
|
2015-09-14 18:12:42 -04:00
|
|
|
|
|
|
|
|
|
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@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`` 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
|
|
|
|
|
|
|
|
|
|
|
2015-09-15 08:33:38 -04:00
|
|
|
|
Branching models
|
|
|
|
|
================
|
|
|
|
|
|
|
|
|
|
Git doesn't assume any particular development model regarding
|
|
|
|
|
branching and merging. Some projects prefer to graduate patches from
|
|
|
|
|
the oldest branch to the newest, some prefer to cherry-pick commits
|
|
|
|
|
backwards, some use squashing (combining a number of commits into
|
|
|
|
|
one). Anything is possible.
|
|
|
|
|
|
|
|
|
|
There are a few examples to start with. `git help workflows
|
|
|
|
|
<https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html>`_
|
|
|
|
|
describes how the very git authors develop git.
|
|
|
|
|
|
|
|
|
|
ProGit book has a few chapters devoted to branch management in
|
|
|
|
|
different projects: `Git Branching - Branching Workflows
|
|
|
|
|
<https://git-scm.com/book/en/Git-Branching-Branching-Workflows>`_ and
|
|
|
|
|
`Distributed Git - Contributing to a Project
|
|
|
|
|
<https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project>`_.
|
|
|
|
|
|
|
|
|
|
There is also a well-known article `A successful Git branching model
|
|
|
|
|
<http://nvie.com/posts/a-successful-git-branching-model/>`_ by Vincent
|
|
|
|
|
Driessen. It recommends a set of very detailed rules on creating and
|
|
|
|
|
managing mainline, topic and bugfix branches. To support the model the
|
|
|
|
|
author implemented `git flow <https://github.com/nvie/gitflow>`_
|
|
|
|
|
extension.
|
|
|
|
|
|
|
|
|
|
|
2015-09-14 18:12:42 -04:00
|
|
|
|
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
|
2016-05-17 20:59:03 -04:00
|
|
|
|
and is being used to develop some Fedora projects. `GitPrep
|
|
|
|
|
<http://gitprep.yukikimoto.com/>`_ is yet another Github clone,
|
|
|
|
|
written in Perl. `Gogs <https://gogs.io/>`_ is written in Go.
|
|
|
|
|
`GitBucket <https://takezoe.github.io/gitbucket/about/>`_ is written
|
|
|
|
|
in Scala.
|
2015-09-14 18:12:42 -04:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
Python Developer's Guide also has a chapter `Mercurial for git
|
|
|
|
|
developers <https://docs.python.org/devguide/gitdevs.html>`_ that
|
|
|
|
|
documents a few differences between git and hg.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 :
|