maint: omit unnecessary to_uchar
[coreutils.git] / HACKING
blob8a49f569c924d122eedba668d69d3c15a789f0c0
1 Coreutils Contribution Guidelines
4 Prerequisites
5 =============
6 You will need the "git" version control tools.  On Fedora-based
7 systems, do "yum install git".  On Debian-based ones install the
8 "git-core" package.  Then run "git --version".  If that says it's
9 older than version 1.4.4, then you'd do well to get a newer version.
10 At worst, just download the latest stable release from
11 https://git-scm.com/ and build from source.
13 For details on building the programs in this package, see the file,
14 README-hacking.
17 Use the latest upstream sources
18 ===============================
19 Base any changes you make on the latest upstream sources.  You can get
20 a copy of the latest with this command:
22     git clone https://git.savannah.gnu.org/git/coreutils.git
23     cd coreutils
25 That downloads the entire repository, including revision control history
26 dating back to 1991.  The repository (the part you download, and which
27 resides in coreutils/.git) currently weighs in at about 30MB.  So you
28 don't want to download it more often than necessary.  Once downloaded,
29 you can get incremental updates by running one of these commands from
30 inside your new coreutils/ directory:
32 If you have made *no* changes:
33     git pull
35 If you *have* made changes and mistakenly committed them to "master",
36 do the following to put your changes on a private branch, "br", and
37 to restore master to its unmodified (relative-to-upstream) state:
38     git checkout -b br
39     git checkout master
40     git reset --hard origin
42 Then "git pull" should work.
45 *Before* you commit changes
46 ===========================
48 In this project, we much prefer patches that automatically record
49 authorship.  That is important not just to give credit where due, but
50 also from a legal standpoint (see below).  To create author-annotated
51 patches with git, you must first tell git who you are.  That information
52 is best recorded in your ~/.gitconfig file.  Edit that file, creating
53 it if needed, and put your name and email address in place of these
54 example values:
56 [user]
57   name = Joe X. User
58   email = joe.user@example.com
61 Your first commit: the quick and dirty way
62 ==========================================
63 First of all, realize that to "commit" a change in git is a purely
64 local operation.  It affects only the local repository (the .git/ dir)
65 in your current coreutils/ hierarchy.
67 To try this out, modify a file or two.  If you create a new file, you'll
68 need to tell git about it with "git add new-file.c".  Commit all changes
69 with "git commit -a".  That prompts you for a log message, which should
70 include a one-line summary, a blank line, and ChangeLog-style entries
71 for all affected files.  More on that below.
73 Once your change is committed, you can create a proper patch that includes
74 a log message and authorship information as well as any permissions
75 changes.  Use this command to save that single, most-recent change set:
77   git format-patch --stdout -1 > DIFF
79 The trouble with this approach is that you've just checked in a change
80 (remember, it's only local) on the "master" branch, and that's where new
81 changes would normally appear when you pull the latest from "upstream".
82 When you "pull" from a remote repository to get the latest, your local
83 changes on "master" may well induce conflicts.   For this reason, you
84 may want to keep "master" free of any local changes, so that you can
85 use it to track unadulterated upstream sources.
87 However, if your cloned directory is for a one-shot patch submission and
88 you're going to remove it right afterwards, then this approach is fine.
89 Otherwise, for a more sustainable (and more generally useful, IMHO)
90 process, read on about "topic" branches.
93 Make your changes on a private "topic" branch
94 =============================================
95 So you checked out coreutils like this:
97   git clone https://git.savannah.gnu.org/git/coreutils.git
99 Now, cd into the coreutils/ directory and run:
101   git checkout -b my-topic
103 That creates the my-topic branch and puts you on it.
104 To see which branch you're on, type "git branch".
105 Right after the clone, you were on "master" (aka the trunk).
106 To get back to the trunk, do this:
108   git checkout master
110 Note 1:
111     Be careful to run "git pull" only when on the "master" branch,
112     not when on a branch.  With newer versions of git, you can't cause
113     trouble if you forget, so this is a good reason to ensure you're
114     using 1.5.3.1 or newer.
116 Note 2:
117     It's best not to try to switch from one branch to another if
118     you have pending (uncommitted) changes.  Sometimes it works,
119     sometimes the checkout will fail, telling you that your local
120     modifications conflict with changes required to switch branches.
121     However, in any case, you will *not* lose your uncommitted changes.
122     Run "git stash" to temporarily hide uncommitted changes in your
123     local directory, restoring a clean working directory.
125 Anyhow, get back onto your just-created branch:
127   git checkout my-topic
129 Now, modify some file and commit it:
131   git commit some-file.c
133 Personally, no matter what package I'm working on, I find it useful to
134 put the ChangeLog entries *only* in the commit log, initially, unless
135 I plan to commit/push right away.  Otherwise, I tend to get unnecessary
136 merge conflicts with each rebase (see below).  In coreutils, I've gone
137 a step further, and no longer maintain an explicit ChangeLog file in
138 version control.  Instead, in a git working directory, you can view
139 ChangeLog information via "git log".  However, each distribution tarball
140 does include a ChangeLog file that is automatically generated from the
141 git logs.
143 So, you've committed a change.  But it's only in your local repository,
144 and only on your "my-topic" branch.  Let's say you wait a day, and
145 then see that someone else changed something and pushed it to the
146 public repository.  Now, you want to update your trunk and "rebase"
147 your changes on the branch so that they are once again relative to the
148 tip of the trunk.  Currently, your branch is attached to the trunk at
149 the next-to-last change set.
151 First: update the trunk from the public repo:
152 [you've first made sure that "git diff" produces no output]
154   git checkout master
155   git pull
157 Now, return to your branch, and "rebase" relative to trunk (master):
159   git checkout my-topic
160   git rebase master
162 If there are no conflicts, this requires no more work from you.
163 However, let's say there was one in ChangeLog, since you didn't
164 follow my advice and modified it anyway.
165 git rebase will tell you there was a conflict and in which
166 file, and instruct you to resolve it and then resume with
167 "git rebase --continue" once that's done.
169 So you resolve as usual, by editing ChangeLog (which has the
170 usual conflict markers), then type "git rebase --continue".
171 That will fail, with a diagnostic telling you to mark
172 the file as "conflict resolved" by doing this:
174   git add ChangeLog
176 Then, finally, you can proceed (possibly onto more conflict resolution,
177 if there are conflicts in other files):
179   git rebase --continue
181 Once it finishes, your changes on the branch are now relative to
182 the tip of the trunk.
184 Now use git format-patch, as above.
187 Amending the most recent change on your private branch
188 ======================================================
189 Let's say you've just committed a change on your private
190 branch, and then realize that something about it is not right.
191 It's easy to adjust:
193   edit your files # this can include running "git add NEW" or "git rm BAD"
194   git commit --amend -a
195   git format-patch --stdout -1 > your-branch.diff
197 That replaces the most recent change-set with the revised one.
201 Coreutils-specific:
203 No more ChangeLog files
204 =======================
205 Do not modify any of the ChangeLog files in coreutils.  Starting in
206 2008, the policy changed.  Before, we would insert the exact same text
207 (or worse, sometimes slightly differing) into both the ChangeLog file
208 and the commit log.  Now we put that information only in the commit log,
209 and generate the top-level ChangeLog file from logs at "make dist" time.
210 As such, there are strict requirements on the form of the commit log
211 messages.
214 Commit log requirements
215 =======================
216 Your commit log should always start with a one-line summary, the second
217 line should be blank, and the remaining lines are usually ChangeLog-style
218 entries for all affected files.  However, it's fine -- even recommended --
219 to write a few lines of prose describing the change, when the summary
220 and ChangeLog entries don't give enough of the big picture.  Omit the
221 leading TABs that you're used to seeing in a "real" ChangeLog file, but
222 keep the maximum line length at 72 or smaller, so that the generated
223 ChangeLog lines, each with its leading TAB, will not exceed 80 columns.
224 As for the ChangeLog-style content, please follow these guidelines:
226   https://www.gnu.org/prep/standards/standards.html#Change-Logs
228 Try to make the summary line fit one of the following forms:
230   program_name: change-description
231   prog1, prog2: change-description
232   doc: change-description
233   tests: change-description
234   build: change-description
235   maint: change-description
237 If your commit fixes a bug, try to find the commit that introduced that
238 bug.  If you do that, add a note in your new commit log saying something
239 like "Introduced by commit v8.12-103-g54cbe6e." and add something like
240 [bug introduced in coreutils-8.13] in the corresponding NEWS blurb.
241 Assuming you found the bug in commit 54cbe6e6, "git describe 54cbe6e6"
242 will print the longer tag-relative string that you'll need.
243 Note that we used to use an 8-byte SHA1 prefix like "54cbe6e6", because
244 that was automatically rendered as a clickable link by "gitk", but with
245 git-1.7.10, the more descriptive version-containing "git describe" format
246 that we now require is also highlighted.
249 Curly braces: use judiciously
250 =============================
251 Omit the curly braces around an "if", "while", "for" etc. body only when
252 that body occupies a single line.  In every other case we require the braces.
253 This ensures that it is trivially easy to identify a single-*statement* loop:
254 each has only one *line* in its body.
256 Omitting braces with a single-line body is fine:
258      while (expr)
259        single_line_stmt ();
261 However, the moment your loop/if/else body extends onto a second line,
262 for whatever reason (even if it's just an added comment), then you should
263 add braces.  Otherwise, it would be too easy to insert a statement just
264 before that comment (without adding braces), thinking it is already a
265 multi-statement loop:
267      while (true)
268        /* comment... */      // BAD: multi-line body without braces
269        single_line_stmt ();
271 Do this instead:
273      while (true)
274        {  /* Always put braces around a multi-line body.  */
275          /* explanation... */
276          single_line_stmt ();
277        }
279 There is one exception: when the second body line is not at the same
280 indentation level as the first body line.
282      if (expr)
283        error (0, 0, _("a diagnostic that would make this line"
284                       " extend past the 80-column limit"));
286 It is safe to omit the braces in the code above, since the
287 further-indented second body line makes it obvious that this is still
288 a single-statement body.
290 To reiterate, don't do this:
292      if (expr)
293        while (expr_2)        // BAD: multi-line body without braces
294          {
295            ...
296          }
298 Do this, instead:
300      if (expr)
301        {
302          while (expr_2)
303            {
304              ...
305            }
306        }
308 However, there is one exception in the other direction, when even a
309 one-line block should have braces.  That occurs when that one-line,
310 brace-less block is an "else" block, and the corresponding "then" block
311 *does* use braces.  In that case, either put braces around the "else"
312 block, or negate the "if"-condition and swap the bodies, putting the
313 one-line block first and making the longer, multi-line block be the
314 "else" block.
316     if (expr)
317       {
318         ...
319         ...
320       }
321     else
322       x = y;    // BAD: braceless "else" with braced "then"
324 This is preferred, especially when the multi-line body is more than a
325 few lines long, because it is easier to read and grasp the semantics of
326 an if-then-else block when the simpler block occurs first, rather than
327 after the more involved block:
329     if (!expr)
330       x = y;                  /* more readable */
331     else
332       {
333         ...
334         ...
335       }
337 If you'd rather not negate the condition, then add braces:
339     if (expr)
340       {
341         ...
342         ...
343       }
344     else
345       {
346         x = y;
347       }
350 Use SPACE-only indentation in all[*] files
351 ==========================================
352 We use space-only indentation in nearly all files.
353 If you use Emacs and your coreutils working directory name matches,
354 this code enables the right mode:
356   ;; In coreutils, indent with spaces everywhere (not TABs).
357   ;; Exceptions: Makefile and ChangeLog modes.
358   (add-hook 'find-file-hook '(lambda ()
359     (if (and buffer-file-name
360              (string-match "/coreutils\\>" (buffer-file-name))
361              (not (string-equal mode-name "Change Log"))
362              (not (string-equal mode-name "Makefile")))
363         (setq indent-tabs-mode nil))))
365 If you use vim (7+ compiled with autocommands), and coreutils working
366 directory name also matches, add the following in ~/.vimrc:
368   " Set GNU style indentation, spaces instead of TABs
369   function! CoreutilsIndent()
370       " Check if 'coreutils' is part of the current working directory
371       if match(getcwd(), "coreutils") > 0
372           " The next 3 lines below set the GNU indentation
373           setlocal cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1
374           setlocal shiftwidth=2
375           setlocal tabstop=8
376           " Coreutils specific, expand TABs with spaces
377           setlocal expandtab
378       endif
379   endfunction
381   autocmd BufEnter *.c,*.h call CoreutilsIndent()
383 [*] Makefile and ChangeLog files are exempt, of course.
386 Send patches to the address listed in --help output
387 ===================================================
388 Please follow the guidelines in the "Sending your patches." section of
389 git's own SubmittingPatches:
391   https://github.com/git/git/blob/master/Documentation/SubmittingPatches
394 Add documentation
395 =================
396 If you add a feature or change some user-visible aspect of a program,
397 document it.  If you add an option, document it both in --help output
398 (i.e., in the usage function that generates the --help output) and in
399 doc/*.texi.  The man pages are generated from --help output, so
400 you shouldn't need to change anything under man/.  User-visible changes
401 are usually documented in NEWS, too.
403 When writing prose (documentation, comments, log entries), use an
404 active voice, not a passive one.  I.e., say "print the frobnozzle",
405 not "the frobnozzle will be printed".
407 Please add comments per the GNU Coding Standard:
408   https://www.gnu.org/prep/standards/html_node/Comments.html
411 Minor syntactic preferences
412 ===========================
413 [I hesitate to write this one down, because it appears to be an
414  acquired taste, at least for native-English speakers.  It seems odd
415  (if not truly backwards) to nearly anyone who doesn't have a strong
416  mathematics background and perhaps a streak of something odd in their
417  character ;-) ]
418 In writing arithmetic comparisons, use "<" and "<=" rather than
419 ">" and ">=".  For some justification, read this:
420   http://www.gelato.unsw.edu.au/archives/git/0505/4507.html
422 const placement:
423 Write "Type const *var", not "const Type *var".
424 FIXME: dig up justification
427 Be nice to translators
428 ======================
429 Don't change translatable strings if you can avoid it.
430 If you must rearrange individual lines (e.g., in multi-line --help
431 strings), extract and create new strings, rather than extracting
432 and moving into existing blocks.  This avoids making unnecessary
433 work for translators.
436 Add tests
437 ==========
438 Nearly every significant change must be accompanied by a test suite
439 addition that exercises it.  If you fix a bug, add at least one test that
440 fails without the patch, but that succeeds once your patch is applied.
441 If you add a feature, add tests to exercise as much of the new code
442 as possible.  If you add a new test file (as opposed to adding a test to
443 an existing test file) add the new test file to 'tests/local.mk'.
444 Note to run tests/misc/new-test in isolation you can do:
446   make check TESTS=tests/misc/new-test SUBDIRS=. VERBOSE=yes
448 Variables that are significant for tests with their default values are:
450   VERBOSE=yes
451   RUN_EXPENSIVE_TESTS=no
452   RUN_VERY_EXPENSIVE_TESTS=no
453   SHELL=/bin/sh
454   NON_ROOT_USERNAME=nobody
455   NON_ROOT_GID=$(id -g $NON_ROOT_USERNAME)
456   COREUTILS_GROUPS=$(id -G)
458 There are hundreds of tests in the tests/ directories.  You can use
459 tests/sample-test as a template, or one of the various Perl-based ones
460 in tests/misc.
462 If writing tests is not your thing, don't worry too much about it,
463 but do provide scenarios, input/output pairs, or whatever, along with
464 examples of running the tool to demonstrate the new or changed feature,
465 and someone else will massage that into a test (writing portable tests
466 can be a challenge).
469 Copyright assignment
470 ====================
471 If your change is significant (i.e., if it adds more than ~10 lines),
472 then you'll have to have a copyright assignment on file with the FSF.
473 Since that involves first an email exchange between you and the FSF,
474 and then the exchange (FSF to you, then back) of an actual sheet of paper
475 with your signature on it, and finally, some administrative processing
476 in Boston, the process can take a few weeks.
478 The forms to choose from are in gnulib's doc/Copyright/ directory.
479 If you want to assign a single change, you should use the file,
480 doc/Copyright/request-assign.changes:
482     https://www.gnu.org/software/gnulib/Copyright/request-assign.changes
484 If you would like to assign past and future contributions to a project,
485 you'd use doc/Copyright/request-assign.future:
487     https://www.gnu.org/software/gnulib/Copyright/request-assign.future
489 You may make assignments for up to four projects at a time.
491 In case you're wondering why we bother with all of this, read this:
493     https://www.gnu.org/licenses/why-assign.html
496 Run "make syntax-check", or even "make distcheck"
497 ================================================
498 Making either of those targets runs many integrity and
499 project-specific policy-conformance tests.  For example, the former
500 ensures that you add no trailing blanks and no uses of certain deprecated
501 functions.  The latter performs all "syntax-check" tests, and also
502 ensures that the build completes with no warnings when using a certain
503 set of gcc -W... options.  Don't even bother running "make distcheck"
504 unless you have a reasonably up to date installation including recent
505 versions of gcc and the linux kernel, and modern GNU tools.
508 Ensure that your changes are indented properly.
509 ===============================================
510 Format the code the way GNU indent does.
511 Filtering most source files through "indent --no-tabs" should
512 induce no change in indentation.  Try not to add any more.
515 Avoid trailing white space
516 ==========================
517 You may notice that the only trailing blanks in coreutils'
518 version-controlled files are in a single directory: tests/pr,
519 which contains expected output from various invocations of pr.
521 Do not add any more trailing blanks anywhere.  While "make syntax-check"
522 will alert you if you slip up, it's better to nip any problem in the
523 bud, as you're typing.  A good way to help you adapt to this rule is
524 to configure your editor to highlight any offending characters in the
525 files you edit.  If you use Emacs, customize its font-lock mode
526 or use its WhiteSpace mode:
528     https://www.emacswiki.org/emacs/WhiteSpace
530 If you use vim, add this to ~/.vimrc:
532     let c_space_errors=1
533     highlight RedundantSpaces ctermbg=red guibg=red
534     match RedundantSpaces /\s\+$\| \+\ze\t/
537 Git can help too, by stopping you from committing any change that would
538 add trailing blanks.  The example pre-commit hook contains code to check
539 for trailing whitespace and spaces before tabs; enable it by moving it
540 to the right place and making sure it is executable:
542     mv .git/hooks/pre-commit.sample .git/hooks/pre-commit
544 With a repository created by git-1.5.6 or older, use this command:
546     chmod +x .git/hooks/pre-commit
548 To manually check for whitespace errors before committing, you can use
550     git diff --check
552 Git also has some settings to enable suitable internal whitespace checks.
553 See the manpage for git-apply for details.
556 -------------------------------------------
558 Miscellaneous useful git commands
559 =================================
561   * gitk: give a graphical view of the revision graph of the current branch
562   * gitk --all: same, but display all branches
563   * git log: to get most of the same info in text form
564   * git log -p: same as above, but with diffs
565   * git log -p SOME_FILE: same as above, but limit to SOME_FILE
566   * git log -p -2 SOME_FILE: same as above, but print only two deltas
567   * git log -p -1: print the most recently committed change set
568   * git format-patch --stdout -1 > FILE: output the most recently committed
569       change set, in a format suitable to be submitted and/or applied via
570       "git am FILE".
571   * git reset --soft HEAD^: Commit the delta required to restore
572       state to the revision just before HEAD (i.e., next-to-last).
573   * git rebase -i master: run this from on a branch, and it gives
574       you an interface with which you can reorder and modify arbitrary
575       change sets on that branch.
577   * if you "misplace" a change set, i.e., via git reset --hard ..., so that
578     it's no longer reachable by any branch, you can use "git fsck" to find
579     its SHA1 and then tag it or cherry-pick it onto an existing branch.
580     For example, run this:
581       git fsck --lost-found HEAD && cd .git/lost-found/commit \
582         && for i in *; do git show $i|grep SOME_IDENTIFYING_STRING \
583         && echo $i; done
584     The "git fsck ..." command creates the .git/lost-found/... hierarchy
585     listing all unreachable objects.  Then the for loop
586     print SHA1s for commits that match via log or patch.
587     For example, say that found 556fbb57216b119155cdda824c98dc579b8121c8,
588     you could run "git show 556fbb57216b119" to examine the change set,
589     or "git checkout -b found 556fbb5721" to give it a branch name.
590     Finally, you might run "git checkout master && git cherry-pick 556fbb5721"
591     to put that change on the tip of "master".
593 -------------------------------------------
595 Finding things to do
596 ====================
597 If you don't know where to start, check out the TODO file for projects
598 that look like they're at your skill-/interest-level.  Another good
599 option is always to improve tests.  You never know what you might
600 uncover when you improve test coverage, and even if you don't find
601 any bugs your contribution is sure to be appreciated.
603 A good way to quickly assess current test coverage, for standard
604 and root only tests, is to follow these steps (requires lcov to be installed):
606   # Do a standard run as the current user
607   make -j$(nproc) coverage
609   # Add the root only tests
610   sudo make -j$(nproc) build-coverage NON_ROOT_USERNAME=$USER SUBDIRS=.
612   # Generate the report with the combined results
613   make gen-coverage
615   # view the HTML report:
616   xdg-open doc/coverage/index.html
618 ========================================================================
619 Copyright (C) 2009-2024 Free Software Foundation, Inc.
621 Permission is granted to copy, distribute and/or modify this document
622 under the terms of the GNU Free Documentation License, Version 1.3 or
623 any later version published by the Free Software Foundation; with no
624 Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
625 Texts.  A copy of the license is included in the "GNU Free
626 Documentation License" file as part of this distribution.