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