You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
479 lines
17 KiB
479 lines
17 KiB
gitworkflows(7) |
|
=============== |
|
|
|
NAME |
|
---- |
|
gitworkflows - An overview of recommended workflows with Git |
|
|
|
SYNOPSIS |
|
-------- |
|
[verse] |
|
git * |
|
|
|
|
|
DESCRIPTION |
|
----------- |
|
|
|
This document attempts to write down and motivate some of the workflow |
|
elements used for `git.git` itself. Many ideas apply in general, |
|
though the full workflow is rarely required for smaller projects with |
|
fewer people involved. |
|
|
|
We formulate a set of 'rules' for quick reference, while the prose |
|
tries to motivate each of them. Do not always take them literally; |
|
you should value good reasons for your actions higher than manpages |
|
such as this one. |
|
|
|
|
|
SEPARATE CHANGES |
|
---------------- |
|
|
|
As a general rule, you should try to split your changes into small |
|
logical steps, and commit each of them. They should be consistent, |
|
working independently of any later commits, pass the test suite, etc. |
|
This makes the review process much easier, and the history much more |
|
useful for later inspection and analysis, for example with |
|
linkgit:git-blame[1] and linkgit:git-bisect[1]. |
|
|
|
To achieve this, try to split your work into small steps from the very |
|
beginning. It is always easier to squash a few commits together than |
|
to split one big commit into several. Don't be afraid of making too |
|
small or imperfect steps along the way. You can always go back later |
|
and edit the commits with `git rebase --interactive` before you |
|
publish them. You can use `git stash push --keep-index` to run the |
|
test suite independent of other uncommitted changes; see the EXAMPLES |
|
section of linkgit:git-stash[1]. |
|
|
|
|
|
MANAGING BRANCHES |
|
----------------- |
|
|
|
There are two main tools that can be used to include changes from one |
|
branch on another: linkgit:git-merge[1] and |
|
linkgit:git-cherry-pick[1]. |
|
|
|
Merges have many advantages, so we try to solve as many problems as |
|
possible with merges alone. Cherry-picking is still occasionally |
|
useful; see "Merging upwards" below for an example. |
|
|
|
Most importantly, merging works at the branch level, while |
|
cherry-picking works at the commit level. This means that a merge can |
|
carry over the changes from 1, 10, or 1000 commits with equal ease, |
|
which in turn means the workflow scales much better to a large number |
|
of contributors (and contributions). Merges are also easier to |
|
understand because a merge commit is a "promise" that all changes from |
|
all its parents are now included. |
|
|
|
There is a tradeoff of course: merges require a more careful branch |
|
management. The following subsections discuss the important points. |
|
|
|
|
|
Graduation |
|
~~~~~~~~~~ |
|
|
|
As a given feature goes from experimental to stable, it also |
|
"graduates" between the corresponding branches of the software. |
|
`git.git` uses the following 'integration branches': |
|
|
|
* 'maint' tracks the commits that should go into the next "maintenance |
|
release", i.e., update of the last released stable version; |
|
|
|
* 'master' tracks the commits that should go into the next release; |
|
|
|
* 'next' is intended as a testing branch for topics being tested for |
|
stability for master. |
|
|
|
There is a fourth official branch that is used slightly differently: |
|
|
|
* 'seen' (patches seen by the maintainer) is an integration branch for |
|
things that are not quite ready for inclusion yet (see "Integration |
|
Branches" below). |
|
|
|
Each of the four branches is usually a direct descendant of the one |
|
above it. |
|
|
|
Conceptually, the feature enters at an unstable branch (usually 'next' |
|
or 'seen'), and "graduates" to 'master' for the next release once it is |
|
considered stable enough. |
|
|
|
|
|
Merging upwards |
|
~~~~~~~~~~~~~~~ |
|
|
|
The "downwards graduation" discussed above cannot be done by actually |
|
merging downwards, however, since that would merge 'all' changes on |
|
the unstable branch into the stable one. Hence the following: |
|
|
|
.Merge upwards |
|
[caption="Rule: "] |
|
===================================== |
|
Always commit your fixes to the oldest supported branch that requires |
|
them. Then (periodically) merge the integration branches upwards into each |
|
other. |
|
===================================== |
|
|
|
This gives a very controlled flow of fixes. If you notice that you |
|
have applied a fix to e.g. 'master' that is also required in 'maint', |
|
you will need to cherry-pick it (using linkgit:git-cherry-pick[1]) |
|
downwards. This will happen a few times and is nothing to worry about |
|
unless you do it very frequently. |
|
|
|
|
|
Topic branches |
|
~~~~~~~~~~~~~~ |
|
|
|
Any nontrivial feature will require several patches to implement, and |
|
may get extra bugfixes or improvements during its lifetime. |
|
|
|
Committing everything directly on the integration branches leads to many |
|
problems: Bad commits cannot be undone, so they must be reverted one |
|
by one, which creates confusing histories and further error potential |
|
when you forget to revert part of a group of changes. Working in |
|
parallel mixes up the changes, creating further confusion. |
|
|
|
Use of "topic branches" solves these problems. The name is pretty |
|
self explanatory, with a caveat that comes from the "merge upwards" |
|
rule above: |
|
|
|
.Topic branches |
|
[caption="Rule: "] |
|
===================================== |
|
Make a side branch for every topic (feature, bugfix, ...). Fork it off |
|
at the oldest integration branch that you will eventually want to merge it |
|
into. |
|
===================================== |
|
|
|
Many things can then be done very naturally: |
|
|
|
* To get the feature/bugfix into an integration branch, simply merge |
|
it. If the topic has evolved further in the meantime, merge again. |
|
(Note that you do not necessarily have to merge it to the oldest |
|
integration branch first. For example, you can first merge a bugfix |
|
to 'next', give it some testing time, and merge to 'maint' when you |
|
know it is stable.) |
|
|
|
* If you find you need new features from the branch 'other' to continue |
|
working on your topic, merge 'other' to 'topic'. (However, do not |
|
do this "just habitually", see below.) |
|
|
|
* If you find you forked off the wrong branch and want to move it |
|
"back in time", use linkgit:git-rebase[1]. |
|
|
|
Note that the last point clashes with the other two: a topic that has |
|
been merged elsewhere should not be rebased. See the section on |
|
RECOVERING FROM UPSTREAM REBASE in linkgit:git-rebase[1]. |
|
|
|
We should point out that "habitually" (regularly for no real reason) |
|
merging an integration branch into your topics -- and by extension, |
|
merging anything upstream into anything downstream on a regular basis |
|
-- is frowned upon: |
|
|
|
.Merge to downstream only at well-defined points |
|
[caption="Rule: "] |
|
===================================== |
|
Do not merge to downstream except with a good reason: upstream API |
|
changes affect your branch; your branch no longer merges to upstream |
|
cleanly; etc. |
|
===================================== |
|
|
|
Otherwise, the topic that was merged to suddenly contains more than a |
|
single (well-separated) change. The many resulting small merges will |
|
greatly clutter up history. Anyone who later investigates the history |
|
of a file will have to find out whether that merge affected the topic |
|
in development. An upstream might even inadvertently be merged into a |
|
"more stable" branch. And so on. |
|
|
|
|
|
Throw-away integration |
|
~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
If you followed the last paragraph, you will now have many small topic |
|
branches, and occasionally wonder how they interact. Perhaps the |
|
result of merging them does not even work? But on the other hand, we |
|
want to avoid merging them anywhere "stable" because such merges |
|
cannot easily be undone. |
|
|
|
The solution, of course, is to make a merge that we can undo: merge |
|
into a throw-away branch. |
|
|
|
.Throw-away integration branches |
|
[caption="Rule: "] |
|
===================================== |
|
To test the interaction of several topics, merge them into a |
|
throw-away branch. You must never base any work on such a branch! |
|
===================================== |
|
|
|
If you make it (very) clear that this branch is going to be deleted |
|
right after the testing, you can even publish this branch, for example |
|
to give the testers a chance to work with it, or other developers a |
|
chance to see if their in-progress work will be compatible. `git.git` |
|
has such an official throw-away integration branch called 'seen'. |
|
|
|
|
|
Branch management for a release |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
Assuming you are using the merge approach discussed above, when you |
|
are releasing your project you will need to do some additional branch |
|
management work. |
|
|
|
A feature release is created from the 'master' branch, since 'master' |
|
tracks the commits that should go into the next feature release. |
|
|
|
The 'master' branch is supposed to be a superset of 'maint'. If this |
|
condition does not hold, then 'maint' contains some commits that |
|
are not included on 'master'. The fixes represented by those commits |
|
will therefore not be included in your feature release. |
|
|
|
To verify that 'master' is indeed a superset of 'maint', use git log: |
|
|
|
.Verify 'master' is a superset of 'maint' |
|
[caption="Recipe: "] |
|
===================================== |
|
`git log master..maint` |
|
===================================== |
|
|
|
This command should not list any commits. Otherwise, check out |
|
'master' and merge 'maint' into it. |
|
|
|
Now you can proceed with the creation of the feature release. Apply a |
|
tag to the tip of 'master' indicating the release version: |
|
|
|
.Release tagging |
|
[caption="Recipe: "] |
|
===================================== |
|
`git tag -s -m "Git X.Y.Z" vX.Y.Z master` |
|
===================================== |
|
|
|
You need to push the new tag to a public Git server (see |
|
"DISTRIBUTED WORKFLOWS" below). This makes the tag available to |
|
others tracking your project. The push could also trigger a |
|
post-update hook to perform release-related items such as building |
|
release tarballs and preformatted documentation pages. |
|
|
|
Similarly, for a maintenance release, 'maint' is tracking the commits |
|
to be released. Therefore, in the steps above simply tag and push |
|
'maint' rather than 'master'. |
|
|
|
|
|
Maintenance branch management after a feature release |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
After a feature release, you need to manage your maintenance branches. |
|
|
|
First, if you wish to continue to release maintenance fixes for the |
|
feature release made before the recent one, then you must create |
|
another branch to track commits for that previous release. |
|
|
|
To do this, the current maintenance branch is copied to another branch |
|
named with the previous release version number (e.g. maint-X.Y.(Z-1) |
|
where X.Y.Z is the current release). |
|
|
|
.Copy maint |
|
[caption="Recipe: "] |
|
===================================== |
|
`git branch maint-X.Y.(Z-1) maint` |
|
===================================== |
|
|
|
The 'maint' branch should now be fast-forwarded to the newly released |
|
code so that maintenance fixes can be tracked for the current release: |
|
|
|
.Update maint to new release |
|
[caption="Recipe: "] |
|
===================================== |
|
* `git checkout maint` |
|
* `git merge --ff-only master` |
|
===================================== |
|
|
|
If the merge fails because it is not a fast-forward, then it is |
|
possible some fixes on 'maint' were missed in the feature release. |
|
This will not happen if the content of the branches was verified as |
|
described in the previous section. |
|
|
|
|
|
Branch management for next and seen after a feature release |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
After a feature release, the integration branch 'next' may optionally be |
|
rewound and rebuilt from the tip of 'master' using the surviving |
|
topics on 'next': |
|
|
|
.Rewind and rebuild next |
|
[caption="Recipe: "] |
|
===================================== |
|
* `git switch -C next master` |
|
* `git merge ai/topic_in_next1` |
|
* `git merge ai/topic_in_next2` |
|
* ... |
|
===================================== |
|
|
|
The advantage of doing this is that the history of 'next' will be |
|
clean. For example, some topics merged into 'next' may have initially |
|
looked promising, but were later found to be undesirable or premature. |
|
In such a case, the topic is reverted out of 'next' but the fact |
|
remains in the history that it was once merged and reverted. By |
|
recreating 'next', you give another incarnation of such topics a clean |
|
slate to retry, and a feature release is a good point in history to do |
|
so. |
|
|
|
If you do this, then you should make a public announcement indicating |
|
that 'next' was rewound and rebuilt. |
|
|
|
The same rewind and rebuild process may be followed for 'seen'. A public |
|
announcement is not necessary since 'seen' is a throw-away branch, as |
|
described above. |
|
|
|
|
|
DISTRIBUTED WORKFLOWS |
|
--------------------- |
|
|
|
After the last section, you should know how to manage topics. In |
|
general, you will not be the only person working on the project, so |
|
you will have to share your work. |
|
|
|
Roughly speaking, there are two important workflows: merge and patch. |
|
The important difference is that the merge workflow can propagate full |
|
history, including merges, while patches cannot. Both workflows can |
|
be used in parallel: in `git.git`, only subsystem maintainers use |
|
the merge workflow, while everyone else sends patches. |
|
|
|
Note that the maintainer(s) may impose restrictions, such as |
|
"Signed-off-by" requirements, that all commits/patches submitted for |
|
inclusion must adhere to. Consult your project's documentation for |
|
more information. |
|
|
|
|
|
Merge workflow |
|
~~~~~~~~~~~~~~ |
|
|
|
The merge workflow works by copying branches between upstream and |
|
downstream. Upstream can merge contributions into the official |
|
history; downstream base their work on the official history. |
|
|
|
There are three main tools that can be used for this: |
|
|
|
* linkgit:git-push[1] copies your branches to a remote repository, |
|
usually to one that can be read by all involved parties; |
|
|
|
* linkgit:git-fetch[1] that copies remote branches to your repository; |
|
and |
|
|
|
* linkgit:git-pull[1] that does fetch and merge in one go. |
|
|
|
Note the last point. Do 'not' use 'git pull' unless you actually want |
|
to merge the remote branch. |
|
|
|
Getting changes out is easy: |
|
|
|
.Push/pull: Publishing branches/topics |
|
[caption="Recipe: "] |
|
===================================== |
|
`git push <remote> <branch>` and tell everyone where they can fetch |
|
from. |
|
===================================== |
|
|
|
You will still have to tell people by other means, such as mail. (Git |
|
provides the linkgit:git-request-pull[1] to send preformatted pull |
|
requests to upstream maintainers to simplify this task.) |
|
|
|
If you just want to get the newest copies of the integration branches, |
|
staying up to date is easy too: |
|
|
|
.Push/pull: Staying up to date |
|
[caption="Recipe: "] |
|
===================================== |
|
Use `git fetch <remote>` or `git remote update` to stay up to date. |
|
===================================== |
|
|
|
Then simply fork your topic branches from the stable remotes as |
|
explained earlier. |
|
|
|
If you are a maintainer and would like to merge other people's topic |
|
branches to the integration branches, they will typically send a |
|
request to do so by mail. Such a request looks like |
|
|
|
------------------------------------- |
|
Please pull from |
|
<url> <branch> |
|
------------------------------------- |
|
|
|
In that case, 'git pull' can do the fetch and merge in one go, as |
|
follows. |
|
|
|
.Push/pull: Merging remote topics |
|
[caption="Recipe: "] |
|
===================================== |
|
`git pull <url> <branch>` |
|
===================================== |
|
|
|
Occasionally, the maintainer may get merge conflicts when they try to |
|
pull changes from downstream. In this case, they can ask downstream to |
|
do the merge and resolve the conflicts themselves (perhaps they will |
|
know better how to resolve them). It is one of the rare cases where |
|
downstream 'should' merge from upstream. |
|
|
|
|
|
Patch workflow |
|
~~~~~~~~~~~~~~ |
|
|
|
If you are a contributor that sends changes upstream in the form of |
|
emails, you should use topic branches as usual (see above). Then use |
|
linkgit:git-format-patch[1] to generate the corresponding emails |
|
(highly recommended over manually formatting them because it makes the |
|
maintainer's life easier). |
|
|
|
.format-patch/am: Publishing branches/topics |
|
[caption="Recipe: "] |
|
===================================== |
|
* `git format-patch -M upstream..topic` to turn them into preformatted |
|
patch files |
|
* `git send-email --to=<recipient> <patches>` |
|
===================================== |
|
|
|
See the linkgit:git-format-patch[1] and linkgit:git-send-email[1] |
|
manpages for further usage notes. |
|
|
|
If the maintainer tells you that your patch no longer applies to the |
|
current upstream, you will have to rebase your topic (you cannot use a |
|
merge because you cannot format-patch merges): |
|
|
|
.format-patch/am: Keeping topics up to date |
|
[caption="Recipe: "] |
|
===================================== |
|
`git pull --rebase <url> <branch>` |
|
===================================== |
|
|
|
You can then fix the conflicts during the rebase. Presumably you have |
|
not published your topic other than by mail, so rebasing it is not a |
|
problem. |
|
|
|
If you receive such a patch series (as maintainer, or perhaps as a |
|
reader of the mailing list it was sent to), save the mails to files, |
|
create a new topic branch and use 'git am' to import the commits: |
|
|
|
.format-patch/am: Importing patches |
|
[caption="Recipe: "] |
|
===================================== |
|
`git am < patch` |
|
===================================== |
|
|
|
One feature worth pointing out is the three-way merge, which can help |
|
if you get conflicts: `git am -3` will use index information contained |
|
in patches to figure out the merge base. See linkgit:git-am[1] for |
|
other options. |
|
|
|
|
|
SEE ALSO |
|
-------- |
|
linkgit:gittutorial[7], |
|
linkgit:git-push[1], |
|
linkgit:git-pull[1], |
|
linkgit:git-merge[1], |
|
linkgit:git-rebase[1], |
|
linkgit:git-format-patch[1], |
|
linkgit:git-send-email[1], |
|
linkgit:git-am[1] |
|
|
|
GIT |
|
--- |
|
Part of the linkgit:git[1] suite
|
|
|