|
|
Coreutils Contribution Guidelines |
|
|
|
|
|
|
|
|
Prerequisites |
|
|
============= |
|
|
You will need the "git" version control tools. On Fedora-based |
|
|
systems, do "yum install git". On Debian-based ones install the |
|
|
"git-core" package. Then run "git --version". If that says it's |
|
|
older than version 1.6.4, then you'd do well to get a newer version. |
|
|
At worst, just download the latest stable release from |
|
|
https: |
|
|
|
|
|
For details on building the programs in this package, see the file, |
|
|
README-hacking. |
|
|
|
|
|
|
|
|
Use the latest upstream sources |
|
|
=============================== |
|
|
Base any changes you make on the latest upstream sources. You can get |
|
|
a copy of the latest with this command: |
|
|
|
|
|
git clone https: |
|
|
cd coreutils |
|
|
|
|
|
That downloads the entire repository, including revision control history |
|
|
dating back to 1991. The repository (the part you download, and which |
|
|
resides in coreutils/.git) currently weighs in at about 30MB. So you |
|
|
don't want to download it more often than necessary. Once downloaded, |
|
|
you can get incremental updates by running one of these commands from |
|
|
inside your new coreutils/ directory: |
|
|
|
|
|
If you have made *no* changes: |
|
|
git pull |
|
|
|
|
|
If you *have* made changes and mistakenly committed them to "master", |
|
|
do the following to put your changes on a private branch, "br", and |
|
|
to restore master to its unmodified (relative-to-upstream) state: |
|
|
git checkout -b br |
|
|
git checkout master |
|
|
git reset --hard origin |
|
|
|
|
|
Then "git pull" should work. |
|
|
|
|
|
|
|
|
|
|
|
=========================== |
|
|
|
|
|
In this project, we much prefer patches that automatically record |
|
|
authorship. That is important not just to give credit where due, but |
|
|
also from a legal standpoint (see below). To create author-annotated |
|
|
patches with git, you must first tell git who you are. That information |
|
|
is best recorded in your ~/.gitconfig file. Edit that file, creating |
|
|
it if needed, and put your name and email address in place of these |
|
|
example values: |
|
|
|
|
|
[user] |
|
|
name = Joe X. User |
|
|
email = joe.user@example.com |
|
|
|
|
|
|
|
|
Your first commit: the quick and dirty way |
|
|
========================================== |
|
|
First of all, realize that to "commit" a change in git is a purely |
|
|
local operation. It affects only the local repository (the .git/ dir) |
|
|
in your current coreutils/ hierarchy. |
|
|
|
|
|
To try this out, modify a file or two. If you create a new file, you'll |
|
|
need to tell git about it with "git add new-file.c". Commit all changes |
|
|
with "git commit -a". That prompts you for a log message, which should |
|
|
include a one-line summary, a blank line, and ChangeLog-style entries |
|
|
for all affected files. More on that below. |
|
|
|
|
|
Once your change is committed, you can create a proper patch that includes |
|
|
a log message and authorship information as well as any permissions |
|
|
changes. Use this command to save that single, most-recent change set: |
|
|
|
|
|
git format-patch --stdout -1 > DIFF |
|
|
|
|
|
The trouble with this approach is that you've just checked in a change |
|
|
(remember, it's only local) on the "master" branch, and that's where new |
|
|
changes would normally appear when you pull the latest from "upstream". |
|
|
When you "pull" from a remote repository to get the latest, your local |
|
|
changes on "master" may well induce conflicts. For this reason, you |
|
|
may want to keep "master" free of any local changes, so that you can |
|
|
use it to track unadulterated upstream sources. |
|
|
|
|
|
However, if your cloned directory is for a one-shot patch submission and |
|
|
you're going to remove it right afterwards, then this approach is fine. |
|
|
Otherwise, for a more sustainable (and more generally useful, IMHO) |
|
|
process, read on about "topic" branches. |
|
|
|
|
|
|
|
|
Make your changes on a private "topic" branch |
|
|
============================================= |
|
|
So you checked out coreutils like this: |
|
|
|
|
|
git clone https: |
|
|
|
|
|
Now, cd into the coreutils/ directory and run: |
|
|
|
|
|
git checkout -b my-topic |
|
|
|
|
|
That creates the my-topic branch and puts you on it. |
|
|
To see which branch you're on, type "git branch". |
|
|
Right after the clone, you were on "master" (aka the trunk). |
|
|
To get back to the trunk, do this: |
|
|
|
|
|
git checkout master |
|
|
|
|
|
Note 1: |
|
|
Be careful to run "git pull" only when on the "master" branch, |
|
|
not when on a branch. With newer versions of git, you can't cause |
|
|
trouble if you forget, so this is a good reason to ensure you're |
|
|
using 1.5.3.1 or newer. |
|
|
|
|
|
Note 2: |
|
|
It's best not to try to switch from one branch to another if |
|
|
you have pending (uncommitted) changes. Sometimes it works, |
|
|
sometimes the checkout will fail, telling you that your local |
|
|
modifications conflict with changes required to switch branches. |
|
|
However, in any case, you will *not* lose your uncommitted changes. |
|
|
Run "git stash" to temporarily hide uncommitted changes in your |
|
|
local directory, restoring a clean working directory. |
|
|
|
|
|
Anyhow, get back onto your just-created branch: |
|
|
|
|
|
git checkout my-topic |
|
|
|
|
|
Now, modify some file and commit it: |
|
|
|
|
|
git commit some-file.c |
|
|
|
|
|
Personally, no matter what package I'm working on, I find it useful to |
|
|
put the ChangeLog entries *only* in the commit log, initially, unless |
|
|
I plan to commit/push right away. Otherwise, I tend to get unnecessary |
|
|
merge conflicts with each rebase (see below). In coreutils, I've gone |
|
|
a step further, and no longer maintain an explicit ChangeLog file in |
|
|
version control. Instead, in a git working directory, you can view |
|
|
ChangeLog information via "git log". However, each distribution tarball |
|
|
does include a ChangeLog file that is automatically generated from the |
|
|
git logs. |
|
|
|
|
|
So, you've committed a change. But it's only in your local repository, |
|
|
and only on your "my-topic" branch. Let's say you wait a day, and |
|
|
then see that someone else changed something and pushed it to the |
|
|
public repository. Now, you want to update your trunk and "rebase" |
|
|
your changes on the branch so that they are once again relative to the |
|
|
tip of the trunk. Currently, your branch is attached to the trunk at |
|
|
the next-to-last change set. |
|
|
|
|
|
First: update the trunk from the public repo: |
|
|
[you've first made sure that "git diff" produces no output] |
|
|
|
|
|
git checkout master |
|
|
git pull |
|
|
|
|
|
Now, return to your branch, and "rebase" relative to trunk (master): |
|
|
|
|
|
git checkout my-topic |
|
|
git rebase master |
|
|
|
|
|
If there are no conflicts, this requires no more work from you. |
|
|
However, let's say there was one in ChangeLog, since you didn't |
|
|
follow my advice and modified it anyway. |
|
|
git rebase will tell you there was a conflict and in which |
|
|
file, and instruct you to resolve it and then resume with |
|
|
"git rebase --continue" once that's done. |
|
|
|
|
|
So you resolve as usual, by editing ChangeLog (which has the |
|
|
usual conflict markers), then type "git rebase --continue". |
|
|
That will fail, with a diagnostic telling you to mark |
|
|
the file as "conflict resolved" by doing this: |
|
|
|
|
|
git add ChangeLog |
|
|
|
|
|
Then, finally, you can proceed (possibly onto more conflict resolution, |
|
|
if there are conflicts in other files): |
|
|
|
|
|
git rebase --continue |
|
|
|
|
|
Once it finishes, your changes on the branch are now relative to |
|
|
the tip of the trunk. |
|
|
|
|
|
Now use git format-patch, as above. |
|
|
|
|
|
|
|
|
Amending the most recent change on your private branch |
|
|
====================================================== |
|
|
Let's say you've just committed a change on your private |
|
|
branch, and then realize that something about it is not right. |
|
|
It's easy to adjust: |
|
|
|
|
|
edit your files # this can include running "git add NEW" or "git rm BAD" |
|
|
git commit --amend -a |
|
|
git format-patch --stdout -1 > your-branch.diff |
|
|
|
|
|
That replaces the most recent change-set with the revised one. |
|
|
|
|
|
|
|
|
|
|
|
Coreutils-specific: |
|
|
|
|
|
No more ChangeLog files |
|
|
======================= |
|
|
Do not modify any of the ChangeLog files in coreutils. Starting in |
|
|
2008, the policy changed. Before, we would insert the exact same text |
|
|
(or worse, sometimes slightly differing) into both the ChangeLog file |
|
|
and the commit log. Now we put that information only in the commit log, |
|
|
and generate the top-level ChangeLog file from logs at "make dist" time. |
|
|
As such, there are strict requirements on the form of the commit log |
|
|
messages. |
|
|
|
|
|
|
|
|
Commit log requirements |
|
|
======================= |
|
|
Your commit log should always start with a one-line summary, the second |
|
|
line should be blank, and the remaining lines are usually ChangeLog-style |
|
|
entries for all affected files. However, it's fine -- even recommended -- |
|
|
to write a few lines of prose describing the change, when the summary |
|
|
and ChangeLog entries don't give enough of the big picture. Omit the |
|
|
leading TABs that you're used to seeing in a "real" ChangeLog file, but |
|
|
keep the maximum line length at 72 or smaller, so that the generated |
|
|
ChangeLog lines, each with its leading TAB, will not exceed 80 columns. |
|
|
As for the ChangeLog-style content, please follow these guidelines: |
|
|
|
|
|
https: |
|
|
|
|
|
Try to make the summary line fit one of the following forms: |
|
|
|
|
|
program_name: change-description |
|
|
prog1, prog2: change-description |
|
|
doc: change-description |
|
|
tests: change-description |
|
|
build: change-description |
|
|
maint: change-description |
|
|
|
|
|
If your commit fixes a bug, try to find the commit that introduced that |
|
|
bug. If you do that, add a note in your new commit log saying something |
|
|
like "Introduced by commit v8.12-103-g54cbe6e." and add something like |
|
|
[bug introduced in coreutils-8.13] in the corresponding NEWS blurb. |
|
|
Assuming you found the bug in commit 54cbe6e6, "git describe 54cbe6e6" |
|
|
will print the longer tag-relative string that you'll need. |
|
|
Note that we used to use an 8-byte SHA1 prefix like "54cbe6e6", because |
|
|
that was automatically rendered as a clickable link by "gitk", but with |
|
|
git-1.7.10, the more descriptive version-containing "git describe" format |
|
|
that we now require is also highlighted. |
|
|
|
|
|
|
|
|
Curly braces: use judiciously |
|
|
============================= |
|
|
Omit the curly braces around an "if", "while", "for" etc. body only when |
|
|
that body occupies a single line. In every other case we require the braces. |
|
|
This ensures that it is trivially easy to identify a single-*statement* loop: |
|
|
each has only one *line* in its body. |
|
|
|
|
|
Omitting braces with a single-line body is fine: |
|
|
|
|
|
while (expr) |
|
|
single_line_stmt (); |
|
|
|
|
|
However, the moment your loop/if/else body extends onto a second line, |
|
|
for whatever reason (even if it's just an added comment), then you should |
|
|
add braces. Otherwise, it would be too easy to insert a statement just |
|
|
before that comment (without adding braces), thinking it is already a |
|
|
multi-statement loop: |
|
|
|
|
|
while (true) |
|
|
|
|
|
single_line_stmt (); |
|
|
|
|
|
Do this instead: |
|
|
|
|
|
while (true) |
|
|
{ |
|
|
|
|
|
single_line_stmt (); |
|
|
} |
|
|
|
|
|
There is one exception: when the second body line is not at the same |
|
|
indentation level as the first body line. |
|
|
|
|
|
if (expr) |
|
|
error (0, 0, _("a diagnostic that would make this line" |
|
|
" extend past the 80-column limit")); |
|
|
|
|
|
It is safe to omit the braces in the code above, since the |
|
|
further-indented second body line makes it obvious that this is still |
|
|
a single-statement body. |
|
|
|
|
|
To reiterate, don't do this: |
|
|
|
|
|
if (expr) |
|
|
while (expr_2) |
|
|
{ |
|
|
... |
|
|
} |
|
|
|
|
|
Do this, instead: |
|
|
|
|
|
if (expr) |
|
|
{ |
|
|
while (expr_2) |
|
|
{ |
|
|
... |
|
|
} |
|
|
} |
|
|
|
|
|
However, there is one exception in the other direction, when even a |
|
|
one-line block should have braces. That occurs when that one-line, |
|
|
brace-less block is an "else" block, and the corresponding "then" block |
|
|
|
|
|
block, or negate the "if"-condition and swap the bodies, putting the |
|
|
one-line block first and making the longer, multi-line block be the |
|
|
"else" block. |
|
|
|
|
|
if (expr) |
|
|
{ |
|
|
... |
|
|
... |
|
|
} |
|
|
else |
|
|
x = y; |
|
|
|
|
|
This is preferred, especially when the multi-line body is more than a |
|
|
few lines long, because it is easier to read and grasp the semantics of |
|
|
an if-then-else block when the simpler block occurs first, rather than |
|
|
after the more involved block: |
|
|
|
|
|
if (!expr) |
|
|
x = y; |
|
|
else |
|
|
{ |
|
|
... |
|
|
... |
|
|
} |
|
|
|
|
|
If you'd rather not negate the condition, then add braces: |
|
|
|
|
|
if (expr) |
|
|
{ |
|
|
... |
|
|
... |
|
|
} |
|
|
else |
|
|
{ |
|
|
x = y; |
|
|
} |
|
|
|
|
|
|
|
|
Use SPACE-only indentation in all[*] files |
|
|
========================================== |
|
|
We use space-only indentation in nearly all files. |
|
|
If you use Emacs and your coreutils working directory name matches, |
|
|
this code enables the right mode: |
|
|
|
|
|
;; In coreutils, indent with spaces everywhere (not TABs). |
|
|
;; Exceptions: Makefile and ChangeLog modes. |
|
|
(add-hook 'find-file-hook '(lambda () |
|
|
(if (and buffer-file-name |
|
|
(string-match "/coreutils\\>" (buffer-file-name)) |
|
|
(not (string-equal mode-name "Change Log")) |
|
|
(not (string-equal mode-name "Makefile"))) |
|
|
(setq indent-tabs-mode nil)))) |
|
|
|
|
|
If you use vim (7+ compiled with autocommands), and coreutils working |
|
|
directory name also matches, add the following in ~/.vimrc: |
|
|
|
|
|
" Set GNU style indentation, spaces instead of TABs |
|
|
function! CoreutilsIndent() |
|
|
" Check if 'coreutils' is part of the current working directory |
|
|
if match(getcwd(), "coreutils") > 0 |
|
|
" The next 3 lines below set the GNU indentation |
|
|
setlocal cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 |
|
|
setlocal shiftwidth=2 |
|
|
setlocal tabstop=8 |
|
|
" Coreutils specific, expand TABs with spaces |
|
|
setlocal expandtab |
|
|
endif |
|
|
endfunction |
|
|
|
|
|
autocmd BufEnter *.c,*.h call CoreutilsIndent() |
|
|
|
|
|
[*] Makefile and ChangeLog files are exempt, of course. |
|
|
|
|
|
|
|
|
Send patches to the address listed in --help output |
|
|
=================================================== |
|
|
Please follow the guidelines in the "Sending your patches." section of |
|
|
git's own SubmittingPatches: |
|
|
|
|
|
https: |
|
|
|
|
|
|
|
|
Add documentation |
|
|
================= |
|
|
If you add a feature or change some user-visible aspect of a program, |
|
|
document it. If you add an option, document it both in --help output |
|
|
(i.e., in the usage function that generates the --help output) and in |
|
|
doc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|