Fossil SCM

fossil-scm / www / gitusers.md
1
# Git to Fossil Translation Guide
2
3
## Introduction
4
5
Fossil shares many similarities with Git. In many cases, the
6
sub-commands are identical: [`fossil bisect`][fbis] does essentially the
7
same thing as [`git bisect`][gbis], for example.
8
9
Yet, Fossil is not merely Git with a bunch of commands misspelled. If
10
that were the case, we could give you a two-column translation table
11
which would tell you [how to say things like “`git reset --hard HEAD`”](#reset) in
12
this funny ol’ Fossil dialect of Git and be done. The purpose of this
13
document is to cover all the cases where there is no simple 1:1 mapping,
14
usually because of intentional design differences in Fossil that prevent
15
it from working exactly like Git. We choose to explain these differences
16
since to understand the conversion, you need to know why each difference
17
exists.
18
19
We focus on practical command examples here, leaving discussions of the
20
philosophical underpinnings that drive these command differences to [another
21
document][fvg]. The [case studies](#cs1) do get a bit philosophical, but
22
it is with the aim of illustrating how these Fossil design differences
23
cause Fossil to behave materially differently from Git in everyday
24
operation.
25
26
We present this from the perspective of Git users moving to Fossil, but
27
it is also possible to read this document as a Fossil user who speaks
28
only pidgin Git, who may often have questions of the form, “Now how do I
29
do X in Git again?”
30
31
This document’s authors are intimately familiar with Fossil, so it is
32
difficult for us to anticipate the perspective of people who are
33
intimately familiar with Git. If you have a lot of prior Git
34
experience, we welcome your contributions and questions on the [Fossil
35
Forum][ffor].
36
37
While we do try to explain Fossil-specific terminology inline here
38
as-needed, you may find it helpful to skim [the Fossil glossary][gloss].
39
It will give you another take on our definitions here, and it may help
40
you to understand some of the other Fossil docs better.
41
42
[fbis]: /help/bisect
43
[gbis]: https://git-scm.com/docs/git-bisect
44
[ffor]: https://fossil-scm.org/forum
45
[fvg]: ./fossil-v-git.wiki
46
47
48
<a id="mwd"></a>
49
## Repositories and Checkouts Are Distinct
50
51
A repository and a check-out are distinct in Fossil, allowing them to be
52
stored in separate directory trees, whereas the two are commingled by
53
default with Git, with the repository stored in a `.git` subdirectory
54
underneath your working directory. This difference shows up in several
55
separate places when it comes to moving from Git to Fossil.
56
57
58
59
#### <a id="cwork" name="scw"></a> Checkout Workflows
60
61
A Fossil repository is an SQLite database storing the entire history of a
62
project. It is not normally stored inside the working tree.
63
A Fossil working tree — [also called a check-out](./glossary.md#check-out) — is a directory
64
that contains a snapshot of your project that you are currently working
65
on, extracted for you from the repository database file by the `fossil`
66
program.
67
68
There are ways to
69
[emulate the Fossil working style in Git](#worktree), but because they’re not
70
designed into the core concept of the tool, Git tutorials usually
71
advocate a switch-in-place working mode instead, so that is how most
72
users end up working with Git. Contrast [Fossil’s check-out workflow
73
document][ckwf] to see the practical differences.
74
75
There is one Git-specific detail we wish to add beyond what that
76
document already covers. This command:
77
78
git checkout some-branch
79
80
…is best given as:
81
82
fossil update some-branch
83
84
…in Fossil. There is a [`fossil checkout`][co] command, but it has
85
[several differences](./co-vs-up.md) that make it less broadly useful
86
than [`fossil update`][up] in everyday operation, so we recommend that
87
Git users moving to Fossil develop a habit of typing `fossil up` rather
88
than `fossil checkout`. That said, one of those differences does match
89
up with Git users’ expectations: `fossil checkout` doesn’t pull changes
90
from the remote repository into the local clone as `fossil update` does.
91
We think this is less broadly useful, but that’s the subject of the next
92
section.
93
94
[ckwf]: ./ckout-workflows.md
95
[co]: /help/checkout
96
97
98
#### <a id="pullup"></a> Update vs Pull
99
100
The closest equivalent to [`git pull`][gpull] is not
101
[`fossil pull`][fpull], but in fact [`fossil up`][up].
102
103
This is because
104
Fossil tends to follow the CVS command design: `cvs up` pulls
105
changes from the central CVS repository and merges them into the local
106
working directory, so that’s what `fossil up` does, too. (This design
107
choice also tends to make Fossil feel comfortable to Subversion
108
expatriates.)
109
110
The `fossil pull` command is simply the reverse of
111
`fossil push`, so that `fossil sync` [is functionally equivalent
112
to](./sync.wiki#sync):
113
114
fossil push ; fossil pull
115
116
There is no implicit “and update the local working directory” step in Fossil’s
117
push, pull, or sync commands, as there is with `git pull`.
118
119
Someone coming from the Git perspective may perceive that `fossil up`
120
has two purposes:
121
122
* Without the optional `VERSION` argument, it updates the working
123
check-out to the tip of the current branch, as `git pull` does.
124
125
* Given a `VERSION` argument, it updates to the named version. If that’s the
126
name of a branch, it updates to the *tip* of that branch, as
127
`git checkout BRANCH` does.
128
129
In fact, these are the same operation, so they’re the same command in
130
Fossil. The first form simply allows the `VERSION` to be implicit: the
131
tip of the current branch.
132
133
We think this is a more sensible command design than `git pull` vs
134
`git checkout`. ([…vs `git checkout` vs `git checkout`!][gcokoan])
135
136
[fpull]: /help/pull
137
[gpull]: https://git-scm.com/docs/git-pull
138
[gcokoan]: https://stevelosh.com/blog/2013/04/git-koans/#s2-one-thing-well
139
140
141
#### <a id="close" name="dotfile"></a> Closing a Check-Out
142
143
The [`fossil close`][close] command dissociates a check-out directory from the
144
Fossil repository database, _nondestructively_ inverting [`fossil open`][open].
145
(Contrast Git’s [closest alternative](#worktree), `git worktree remove`, which *is*
146
destructive!) This Fossil command does not
147
remove the managed files, and unless you give the `--force`
148
option, it won’t let you close the check-out with uncommitted changes to
149
those managed files.
150
151
The `close` command also refuses to run without `--force` when you have
152
certain other precious per-checkout data that Fossil stores in the
153
`.fslckout` file at the root of a check-out directory. This is an SQLite
154
database that keeps track of local state such as what version you have
155
checked out, the contents of the [stash] for that working directory, the
156
[undo] buffers, per-checkout [settings][set], and so forth. The stash
157
and undo buffers are considered precious uncommitted changes,
158
so you have to force Fossil to discard these as part of closing the
159
check-out.
160
161
Thus, `.fslckout` is not the same thing as `.git`!
162
163
In native Windows builds of Fossil — that is, excluding Cygwin and WSL
164
builds, which follow POSIX conventions — this file is called `_FOSSIL_`
165
instead to get around the historical 3-character extension limit with
166
certain legacy filesystems.
167
168
Closing a check-out directory is a rare operation. One use case
169
is that you’re about to delete the directory, so you want Fossil to forget about it
170
for the purposes of commands like [`fossil all`][all]. Even that isn’t
171
necessary, because Fossil will detect that this has happened and forget
172
the working directory for you.
173
174
[all]: /help/all
175
176
177
#### <a id="worktree"></a> Git Worktrees
178
179
There are at least three different ways to get [Fossil-style multiple
180
check-out directories][mcw] with Git.
181
182
The old way is to simply symlink the `.git` directory between working
183
trees:
184
185
mkdir ../foo-branch
186
ln -s ../actual-clone-dir/.git .
187
git checkout foo-branch
188
189
The symlink trick has a number of problems, the largest being that
190
symlinks weren’t available on Windows until Vista, and until the Windows
191
10 Creators Update was released in spring of 2017, you had to be an
192
Administrator to use the feature besides. ([Source][wsyml]) Git 2.5 solved
193
this problem back when Windows XP was Microsoft’s current offering
194
by adding the `git-worktree` command:
195
196
git worktree add ../foo-branch foo-branch
197
cd ../foo-branch
198
199
That is approximately equivalent to this in Fossil:
200
201
mkdir ../foo-branch
202
cd ../foo-branch
203
fossil open /path/to/repo.fossil foo-branch
204
205
The Fossil alternative is wordier, but since this tends to be one-time setup,
206
not something you do everyday, the overhead is insignificant. This author keeps a “scratch” check-out
207
for cases where it’s inappropriate to reuse the “trunk” check-out,
208
isolating all of my expedient switch-in-place actions to that one
209
working directory. Since the other peer check-outs track long-lived
210
branches, and that set rarely changes once a development machine is set
211
up, I rarely pay the cost of these wordier commands.
212
213
That then leads us to the closest equivalent in Git to [closing a Fossil
214
check-out](#close):
215
216
git worktree remove .
217
218
Note, however, that unlike `fossil close`, once the Git command
219
determines that there are no uncommitted changes, it blows away all of
220
the checked-out files! Fossil’s alternative is shorter, easier to
221
remember, and safer.
222
223
There’s another way to get Fossil-like separate worktrees in Git:
224
225
git clone --separate-git-dir repo.git https://example.com/repo
226
227
This allows you to have your Git repository directory entirely separate
228
from your working tree, with `.git` in the check-out directory being a
229
file that points to `../repo.git`, in this example.
230
231
[mcw]: ./ckout-workflows.md#mcw
232
[wsyml]: https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
233
234
235
#### <a id="iip"></a> Init in Place
236
237
To illustrate the differences that Fossil’s separation of repository
238
from working directory creates in practice, consider this common Git “init in place”
239
method for creating a new repository from an existing tree of files,
240
perhaps because you are placing that project under version control for
241
the first time:
242
243
cd long-established-project
244
git init
245
git add *
246
git commit -m "Initial commit of project."
247
248
The closest equivalent in Fossil is:
249
250
cd long-established-project
251
fossil init .fsl
252
fossil open --force .fsl
253
fossil add *
254
fossil ci -m "Initial commit of project."
255
256
Note that unlike in Git, you can abbreviate the “`commit`” command in
257
Fossil as “`ci`” for compatibility with CVS, Subversion, etc.
258
259
This creates a `.fsl` repo DB at the root of the project check-out to
260
emulate the `.git` repo dir. We have to use the `--force` flag on
261
opening the new repo because Fossil expects you to open a repo into an
262
empty directory in order to avoid spamming the contents of a repo over
263
an existing directory full of files. Here, we know the directory
264
contains files that will soon belong in the repository, though, so we
265
override this check. From then on, Fossil works like Git, for the
266
purposes of this example.
267
268
We’ve drawn this example to create a tight parallel between Fossil and
269
Git, not to commend this `.fsl`-at-project-root trick to you. A better
270
choice would be `~/museum/home/long-established-project.fossil`, if
271
you’re following [the directory scheme exemplified in the glossary](./glossary.md#repository). That said, it
272
does emphasize an earlier point: Fossil doesn’t care where you put the
273
repo DB file or what you name it.
274
275
276
[clone]: /help/clone
277
[close]: /help/close
278
[gloss]: ./glossary.md
279
[open]: /help/open
280
[set]: /help/setting
281
[server]: /help/server
282
[stash]: /help/stash
283
[undo]: /help/undo
284
285
286
## <a id="log"></a> Fossil’s Timeline Is the “Log”
287
288
Git users often need to use the `git log` command to dig linearly through
289
commit histories due to its [weak data model][wdm], giving [O(n)
290
performance][ocomp].
291
292
Fossil parses a huge amount of information out of commits that allow it
293
to produce its [timeline CLI][tlc] and [its `/timeline` web view][tlw]
294
using indexed SQL lookups, which generally have the info you would have
295
to manually extract from `git log`, produced much more quickly than Git
296
can, all else being equal: operations over [SQLite’s B-tree data structures][btree]
297
generally run in O(log n) time, faster than O(n) for equal *n* when the
298
constants are equal.
299
300
Yet the constants are *not* equal because Fossil
301
reads from a single disk file rather than visit potentially many
302
files in sequence as Git must, so the OS’s buffer cache can result in
303
[still better performance][35pct].
304
305
Unlike Git’s log, Fossil’s timeline shows info across all branches by
306
default, a feature for maintaining better situational awareness.
307
It is possible to restrict the timeline to a single branch using `fossil timeline -b`.
308
Similarly, to restrict the timeline using the web UI equivalent,
309
click the name of a branch on the `/timeline` or `/brlist` page. (Or
310
manually, by adding the `r=` query parameter.) Note that even in this
311
case, the Fossil timeline still shows other branches where they interact
312
with the one you’ve referenced in this way; again, better situational
313
awareness.
314
315
316
#### <a id="emu-log"></a> Emulating `git log`
317
318
If you truly need a backwards-in-time-only view of history in Fossil to
319
emulate `git log`, this is as close as you can currently come:
320
321
fossil timeline parents current
322
323
Again, though, this isn’t restricted to a single branch, as `git log`
324
is.
325
326
Another useful rough equivalent is:
327
328
git log --raw
329
fossil time -v
330
331
This shows what changed in each version, though Fossil’s view is more a
332
summary than a list of raw changes. To dig deeper into single commits,
333
you can use Fossil’s [`info` command][infoc] or its [`/info` view][infow].
334
335
Inversely, you may more exactly emulate the default `fossil timeline`
336
output with `git log --name-status`.
337
338
339
#### <a id="whatchanged"></a> What Changed?
340
341
A related — though deprecated — command is `git whatchanged`, which gives results similar to
342
`git log --raw`, so we cover it here.
343
344
Though there is no `fossil whatchanged` command, the same sort of
345
information is available. For example, to pull the current changes from
346
the remote repository and then inspect them before updating the local
347
working directory, you might say this in Git:
348
349
git fetch
350
git whatchanged ..@{u}
351
352
…which you can approximate in Fossil as:
353
354
fossil pull
355
fossil up -n
356
fossil diff --from tip
357
358
To invert the `diff` to show a more natural patch, the command needs to
359
be a bit more complicated, since you can’t currently give `--to`
360
without `--from`.
361
362
fossil diff --from current --to tip
363
364
Rather than use the “dry run” form of [the `update` command][up], you can
365
say:
366
367
fossil timeline after current
368
369
…or if you want to restrict the output to the current branch:
370
371
fossil timeline descendants current
372
373
374
#### <a id="ckin-names"></a> Symbolic Check-In Names
375
376
Note the use of [human-readable symbolic version names][scin] in Fossil
377
rather than [Git’s cryptic notations][gcn].
378
379
For a more dramatic example of this, let us ask Git, “What changed since the
380
beginning of last month?” being October 2020 as I write this:
381
382
git log master@{2020-10-01}..HEAD
383
384
That’s rather obscure! Fossil answers the same question with a simpler
385
command:
386
387
fossil timeline after 2020-10-01
388
389
You may need to add `-n 0` to bypass the default output limit of
390
`fossil timeline`, 20 entries. Without that, this command reads
391
almost like English.
392
393
Some Git users like to write commands like the above so:
394
395
git log @{2020-10-01}..@
396
397
Is that better? “@” now means two different things: an at-time reference
398
and a shortcut for `HEAD`!
399
400
If you are one of those that like short commands, Fossil’s method is
401
less cryptic: it lets you shorten words in most cases up to the point
402
that they become ambiguous. For example, you may abbreviate the last
403
`fossil` command in the prior section:
404
405
fossil tim d c
406
407
…beyond which the `timeline` command becomes ambiguous with `ticket`.
408
409
Some Fossil users employ shell aliases, symlinks, or scripts to shorten
410
the command still further:
411
412
alias f=fossil
413
f tim d c
414
415
Granted, that’s rather obscure, but you you can also choose something
416
intermediate like “`f time desc curr`”, which is reasonably clear.
417
418
[35pct]: https://www.sqlite.org/fasterthanfs.html
419
[btree]: https://sqlite.org/btreemodule.html
420
[gcn]: https://git-scm.com/docs/gitrevisions
421
[infoc]: /help/info
422
[infow]: /help/www/info
423
[ocomp]: https://www.bigocheatsheet.com/
424
[tlc]: /help/timeline
425
[tlw]: /help/www/timeline
426
[up]: /help/update
427
[wdm]: ./fossil-v-git.wiki#durable
428
429
430
## <a id="dhead"></a> Detached HEAD State
431
432
The SQL indexes in Fossil which we brought up above have a useful
433
side benefit: you cannot have a [detached HEAD state][gdh] in Fossil,
434
the source of untold pain and data loss in Git. It simply cannot be done
435
in Fossil, because the indexes always let us find our way back into the
436
hash tree.
437
438
439
## <a id="slcom"></a> Summary Line Convention in Commit Comments
440
441
The Git convention of a [length-limited summary line][lsl] at the start
442
of commit comments is not enforced or obeyed by default in Fossil.
443
However, there is a setting under Admin → Timeline → “Truncate comment
444
at first blank line (Git-style)” to change this for `/timeline`
445
displays. Alternately, you could enable the “Allow block-markup in
446
timeline” setting under Admin → Timeline, then apply [local skin
447
customizations][cskin] to put that first comment in bold or whatever
448
suits.
449
450
Because this isn’t a typical Fossil convention, you’re likely to find
451
other odd differences between it and Git-based infrastructure. For
452
instance, Vim doesn’t ship with syntax support for Fossil commit
453
messages if you set `EDITOR=vim` in your shell environment, so you won’t
454
get over-limit highlighting for first-line text beyond the 50th
455
character and such, because it doesn’t recognize Fossil commit messages
456
and apply similar rules as to Git commit messages.
457
458
[cskin]: ./customskin.md
459
[lsl]: https://chris.beams.io/posts/git-commit/#limit-50
460
461
462
<a id="autocommit"></a>
463
## Fossil Never Auto-Commits
464
465
There are several features in Git besides its `commit` command that
466
produce a new commit to the repository, and by default, they do it
467
without prompting or even asking for a commit message. These include
468
Git’s [`rebase`](#rebase), `merge`, and [`cherrypick`](#cpickrev)
469
commands, plus the [commit splitting](#comsplit) sub-feature
470
“`git commit -p`”.
471
472
Fossil never does this, on firm philosophical grounds: we wish to be
473
able to test that each potentially repository-changing command does not
474
break anything _before_ freezing it immutably into the [Merkle
475
tree](./blockchain.md). Where Fossil has equivalent commands, they
476
modify the checkout tree alone, requiring a separate `commit` command
477
afterward, withheld until the user has satisfied themselves that the
478
command’s result is correct.
479
480
We believe this is the main reason Git lacks an [autosync](#autosync)
481
feature: making push a manual step gives the user a chance to rewrite
482
history after triggering one of these autocommits locally, should the
483
automatic commit fail to work out as expected. Fossil chooses the
484
inverse path under the philosophy that commits are *commitments,* not
485
something you’re allowed to go back and rewrite later.
486
487
This is also why there is no automatic commit message writing feature in
488
Fossil, as in these autocommit-triggering Git commands. The user is
489
meant to write the commit message by hand after they are sure it’s
490
correct, in clear-headed retrospective fashion. Having the tool do it
491
prospectively before one can test the result is simply backwards.
492
493
494
<a id="staging"></a>
495
## There Is No Staging Area
496
497
Fossil omits the "Git index" or "staging area" concept. When you
498
type "`fossil commit`" _all_ changes in your check-out are committed,
499
by default. There is no need for the "-a" option as with Git.
500
501
If you only want to commit _some_ of the changes, list the names
502
of the files or directories you want to commit as arguments, like this:
503
504
fossil commit src/feature.c doc/feature.md examples/feature
505
506
Note that the last element is a directory name, meaning “any changed
507
file under the `examples/feature` directory.”
508
509
510
<a id="comsplit"></a>
511
## Commit Splitting
512
513
[Git’s commit splitting features][gcspl] rely on
514
other features of Git that Fossil purposefully lacks, as covered in the
515
prior two sections: [autocommit](#autocommit) and [the staging
516
area](#staging).
517
518
While there is no direct Fossil equivalent for
519
`git add -p`, `git commit -p`, or `git rebase -i`, you can get the same
520
effect by converting an uncommitted change set to a patch and then
521
running it through [Patchouli].
522
523
Rather than use `fossil diff -i` to produce such a patch, a safer and
524
more idiomatic method would be:
525
526
fossil stash save -m 'my big ball-o-hackage'
527
fossil stash diff > my-changes.patch
528
529
That stores your changes in the stash, then lets you operate on a copy
530
of that patch. Each time you re-run the second command, it will take the
531
current state of the working directory into account to produce a
532
potentially different patch, likely smaller because it leaves out patch
533
hunks already applied.
534
535
In this way, the combination of working tree and stash replaces the need
536
for Git’s index feature.
537
538
We believe we know how to do commit splitting in a way compatible with
539
the Fossil philosophy, without following Git’s ill-considered design
540
leads. It amounts to automating the above process through an interactive
541
variant of [`fossil stash apply`][stash], as currently prototyped in the
542
third-party tool [`fnc`][fnc] and [its interactive `stash`
543
command][fncsta]. We merely await someone’s [contribution][ctrb] of this
544
feature into Fossil proper.
545
546
[ctrb]: https://fossil-scm.org/fossil/doc/trunk/www/contribute.wiki
547
[fnc]: https://fnc.bsdbox.org/
548
[fncsta]: https://fnc.bsdbox.org/uv/doc/fnc.1.html#stash
549
[gcspl]: https://git-scm.com/docs/git-rebase#_splitting_commits
550
[Patchouli]: https://pypi.org/project/patchouli/
551
552
553
<a id="bneed"></a>
554
## Create Branches at Point of Need, Rather Than Ahead of Need
555
556
Fossil prefers that you create new branches as part of the first commit
557
on that branch:
558
559
fossil commit --branch my-branch
560
561
If that commit is successful, your local check-out directory is then
562
switched to the tip of that branch, so subsequent commits don’t need the
563
“`--branch`” option. You simply say `fossil commit` again to continue
564
adding commits to the tip of that branch.
565
566
To switch back to the parent branch, say something like:
567
568
fossil update trunk
569
570
(This is approximately equivalent to `git checkout master`.)
571
572
Fossil does also support the Git style, creating the branch ahead of
573
need:
574
575
fossil branch new my-branch
576
fossil up my-branch
577
...work on first commit...
578
fossil commit
579
580
This is more verbose, giving the same overall effect though the initial
581
actions are inverted: create a new branch for the first commit, switch
582
the check-out directory to that branch, and make that first commit. As
583
above, subsequent commits are descendants of that initial branch commit.
584
We think you’ll agree that creating a branch as part of the initial
585
commit is simpler.
586
587
Fossil also allows you to move a check-in to a different branch
588
*after* you commit it, using the "`fossil amend`" command.
589
For example:
590
591
fossil amend current --branch my-branch
592
593
This works by inserting a tag into the repository that causes the web UI
594
to relabel commits from that point forward with the new name. Like Git,
595
Fossil’s fundamental data structure is the interlinked DAG of commit
596
hashes; branch names are supplemental data for making it easier for the
597
humans to understand this DAG, so this command does not change the core
598
history of the project, only annotate it for better display to the
599
humans.
600
601
(The version string “current” is one of the [special check-in names][scin] in Fossil. See
602
that document for the many other names you can give to “`amend`”, or
603
indeed to any other Fossil command documented to accept a `VERSION` or
604
`NAME` string.)
605
606
[scin]: ./checkin_names.wiki
607
608
609
<a id="syncall"></a>
610
## Sync Is All-or-Nothing
611
612
Fossil does not support the concept of syncing, pushing, or pulling
613
individual branches. When you sync/push/pull in Fossil, it
614
processes all artifacts in its hash tree:
615
branches, tags, wiki articles, tickets, forum posts, technotes…
616
This is [not quite “everything,” full stop][bu], but it’s close.
617
[Fossil is an AP-mode system][capt], which in this case means it works
618
*very hard* to ensure that all repos are as close to identical as it can
619
make them under this eventually-consistent design philosophy.
620
621
Branch *names* sync automatically in Fossil, not just the
622
content of those branches. That means this common Git command:
623
624
git push origin master
625
626
…is simply this in Fossil:
627
628
fossil push
629
630
Fossil doesn’t need to be told what to push or where to push it: it just
631
keeps using the same remote server URL you gave it last
632
until you [tell it to do something different][rem]. It pushes all
633
branches, not just one named local branch.
634
635
[capt]: ./cap-theorem.md
636
[rem]: /help/remote
637
638
639
<a id="autosync"></a>
640
## Autosync
641
642
Fossil’s [autosync][wflow] feature, normally enabled, has no
643
equivalent in Git. If you want Fossil to behave like Git, you can turn
644
it off:
645
646
fossil set autosync 0
647
648
Let’s say that you have a typical server-and-workstations model with two
649
working clones on different machines, that you have disabled autosync,
650
and that this common sequence then occurs:
651
652
1. Alice commits to her local clone and *separately* pushes the change
653
up to Condor — their central server — in typical Git fashion.
654
2. Bob does the same.
655
3. Alice brings Bob’s changes down from Condor with “`fossil pull`,” sees
656
what he did to their shared working branch, and becomes most wrathful.
657
(Tsk, tsk.)
658
659
We’ll get to what you do about this situation [below](#reset), but for
660
now let us focus on the fact that disabling autosync makes it easier for
661
[forks] to occur in the development history. If all three machines had
662
been online and syncing at the time the sequence above began, Bob would
663
have been warned in step 2 that committing to the central repo would
664
create a fork and would be invited to fix it before committing.
665
Likewise, it would allow Fossil to warn Alice about the new
666
tip-of-branch commit the next time she triggers an implicit autosync at
667
step 3, giving her a chance to bring Bob’s changes down in a
668
non-conflicting manner, allowing work to proceed with minimal fuss.
669
670
Fossil, being a distributed version control system, cannot guarantee
671
that sequence of events. Because it allows Alice’s work to proceed
672
asynchronously, it gives her the chance to create *another* inadvertent
673
fork before she can trigger an autosync. This is not a serious problem;
674
Fossil resolves it the same way as with Bob, by inviting her to fix this
675
second fork in the same manner as it did with Bob. It gets both parties
676
back onto a single track as expeditiously as possible by moving the
677
synchronization point out of the expensive human-time workflow and into
678
the software system, where it’s cheapest to resolve.
679
680
Autosync provides Fossil with most of the advantages of a centralized
681
version control system while retaining the advantages of distributed
682
version control:
683
684
1. Your work stays synced up with your coworkers’ efforts as long as your
685
machine can connect to the remote repository. At need, you can go
686
off-network and continue work atop the last version you synced with
687
the remote.
688
689
2. You get implicit off-machine backup of your commits. Unlike
690
centralized version control, though, you can still work while
691
disconnected; your changes will sync up with the remote once you get
692
back online.
693
694
3. Because there is [little distinction][bu] between the clones in the Fossil
695
model — unlike in Git, where clones often quickly diverge from each
696
other, quite possibly on purpose — the backup advantage applies in inverse
697
as well: if the remote server falls over dead, one of those with a
698
clone of that repository can stand it back up, and everyone can get
699
back to work simply by re-pointing their local repo at the new
700
remote. If the failed remote comes back later, it can sync with the
701
new central version, then perhaps take over as the primary source of
702
truth once again.
703
704
[bu]: ./backup.md
705
[forks]: ./branching.wiki
706
[setup]: ./caps/admin-v-setup.md#apsu
707
[wflow]: ./concepts.wiki#workflow
708
709
710
<a id="reset"></a>
711
## Resetting the Repository
712
713
Extending from [the prior item](#syncall), you may correctly infer that
714
“[delete the project and download a fresh copy][x1597]” has no part in
715
the Fossil Way. Ideally, you should never find yourself forced into
716
desperate measures like this:(^Parsing the output of `fossil status` is
717
usually a mistake since it relies on a potentially unstable interface.
718
We make no guarantee that there will always be a line beginning with
719
“`repo`” and that it will be separated from the repository’s file name
720
by a colon. The simplified example above is also liable to become
721
confused by whitespace in file names.)
722
723
724
```
725
$ repo=$(fossil status | grep ^repo | cut -f2 -d:)
726
$ url=$(fossil remote)
727
$ fossil close # Stop here and think if it warns you!
728
$ mv $repo ${repo}.old
729
$ fossil clone $url $repo
730
$ fossil open --force $repo
731
```
732
733
What, then, should you as a Git transplant do instead when you find
734
yourself reaching for “`git reset`”?
735
736
Since the correct answer to that depends on why you think it’s a good
737
solution to your immediate problem, we’ll take our motivating scenario
738
from the problem setup above, where we discussed Fossil’s [autosync]
739
feature. Let us further say Alice’s pique results from a belief that
740
Bob’s commit is objectively wrong-headed and should be expunged
741
henceforth. Since Fossil goes out of its way to ensure that [commits are
742
durable][wdm], it should be no further surprise that there is no easier
743
method to reset Bob’s clone in favor of Alice’s than the above sequence
744
in Fossil’s command set. Except in extreme situations, we believe that
745
sort of thing is unnecessary.
746
747
Instead, Bob can say something like this:
748
749
```
750
fossil amend --branch MISTAKE --hide --close -m "mea culpa" tip
751
fossil up trunk
752
fossil push
753
```
754
755
Unlike in Git, the “`amend`” command doesn’t modify prior committed
756
artifacts. Bob’s first command doesn’t delete anything, merely tells
757
Fossil to hide his mistake from timeline views by inserting a few new
758
records into the local repository to change how the client interprets
759
the data it finds there henceforth.(^One to change the tag marking this
760
commit’s branch name to “`MISTAKE`,” one to mark that branch as hidden,
761
and one to close it to further commits.)
762
763
Bob’s second command switches his working directory back to the prior
764
commit on that branch. We’re presuming it was “`trunk`” for the sake of
765
the example, but it works for any parent branch name. The command works
766
because the name “`trunk`” now means something different to Fossil by
767
virtue of the first command.
768
769
Bob’s third command pushes the changes up to the central machine to
770
inform everyone else of his amendment.(^Amendments don’t autosync in
771
Fossil because they don’t change any previous commits, allowing the
772
other clones to continue working safely with their existing commit
773
hashes.)
774
775
In this scheme, Alice then needs to say “`fossil update trunk`” in order
776
to return her check-out’s parent commit to the previous version lest her
777
next attempted commit land atop this mistake branch. The fact that Bob
778
marked the branch as closed will prevent that from going through, cluing
779
Alice into what she needs to do to remedy the situation, but that merely
780
shows why it’s a better workflow if Alice makes the amendment herself:
781
782
```
783
fossil amend --branch MISTAKE --hide --close \
784
-m "shunt Bob’s erroneous commit off" tip
785
fossil up trunk
786
fossil push
787
```
788
789
Then she can fire off an email listing Bob’s assorted failings and go
790
about her work. This asynchronous workflow solves the problem without
791
requiring explicit coordination with Bob. When he gets his email, he can
792
then say “`fossil up trunk`” himself, which by default will trigger an
793
autosync, pulling down Alice’s amendments and getting him back onto her
794
development track.
795
796
Remember that [branch names need not be unique](#btnames) in Fossil. You
797
are free to reuse this “`MISTAKE`” branch name as often as you need to.
798
799
[autosync]: #autosync
800
[x1597]: https://xkcd.com/1597/
801
802
803
<a id="trunk"></a>
804
## The Main Branch Is Called "`trunk`"
805
806
In Fossil, the default name for the main branch
807
is "`trunk`". The "`trunk`" branch in Fossil corresponds to the
808
"`master`" branch in stock Git or to [the “`main`” branch in GitHub][mbgh].
809
810
Because the `fossil git export` command has to work with both stock Git
811
and with GitHub, Fossil uses Git’s traditional default rather than
812
GitHub’s new default: your Fossil repo’s “trunk” branch becomes “master”
813
when [mirroring to GitHub][mirgh] unless you give the `--mainbranch`
814
option.
815
816
We do not know what happens on subsequent exports if you later rename
817
this branch on the GitHub side.
818
819
[mbgh]: https://github.com/github/renaming
820
[mirgh]: ./mirrortogithub.md
821
822
823
<a id="unmanaged"></a>
824
## Status Does Not Show Unmanaged Files
825
826
The "`fossil status`" command shows you what files in your check-out have
827
been edited and scheduled for adding or removing at the next commit.
828
But unlike "`git status`", the "`fossil status`" command does not warn
829
you about unmanaged files in your local check-out. There is a separate
830
"`fossil extras`" command for that.
831
832
833
<a id="rebase"></a>
834
## There Is No Rebase
835
836
Fossil does not support rebase, [on purpose][3].
837
838
This is a deliberate design decision that the Fossil community has
839
thought about carefully and discussed many times, resulting in the
840
linked document. If you are fond of rebase, you should read it carefully
841
before expressing your views: it not only answers many of the common
842
arguments in favor of rebase known at the time the document’s first
843
draft was written, it’s been revised multiple times to address less
844
common objections as well. Chances are not good that you are going to
845
come up with a new objection that we haven’t already considered and
846
addressed there.
847
848
There is only one sub-feature of `git rebase` that is philosophically
849
compatible with Fossil yet which currently has no functional equivalent.
850
We [covered this and the workaround for its lack](#comsplit) above.
851
852
[3]: ./rebaseharm.md
853
854
855
<a id="cdiff"></a>
856
## Colorized Diffs
857
858
When you run `git diff` on an ANSI X3.64 capable terminal, it uses color
859
to distinguish insertions, deletions, and replacements, but as of this
860
writing, `fossil diff` produces traditional uncolored [unified diff
861
format][udiff] output, suitable for producing a [patch file][pfile].
862
863
There are [many methods](./colordiff.md) for solving this.
864
Viewed this way, Fossil doesn’t lack colorized diffs, it simply has
865
*one* method where they *aren’t* colorized.
866
867
[pfile]: https://en.wikipedia.org/wiki/Patch_(Unix)
868
[udiff]: https://en.wikipedia.org/wiki/Diff#Unified_format
869
870
871
## <a id="show"></a> Showing Information About Commits
872
873
While there is no direct equivalent to Git’s “`show`” command, similar
874
functionality is present in Fossil under other commands:
875
876
877
#### <a id="patch"></a> Show a Patch for a Commit
878
879
git show -p COMMIT_ID
880
881
…gives much the same output as
882
883
fossil diff --checkin COMMIT_ID
884
885
…only without the patch email header. Git comes out of the [LKML] world,
886
where emailing a patch is a normal thing to do. Fossil is [designed for
887
cohesive teams][devorg] where drive-by patches are rarer.
888
889
You can use any of [Fossil’s special check-in names][scin] in place of
890
the `COMMIT_ID` in this and later examples. Fossil docs usually say
891
“`VERSION`” or “`NAME`” where this is allowed, since the version string
892
or name might not refer to a commit ID, but instead to a forum post, a
893
wiki document, etc. For instance, the following command answers the question “What did
894
I just commit?”
895
896
fossil diff --checkin tip
897
898
…or equivalently using a different symbolic commit name:
899
900
fossil diff --from prev
901
902
[devorg]: ./fossil-v-git.wiki#devorg
903
[LKML]: https://lkml.org/
904
905
906
#### <a id="cmsg"></a> Show a Specific Commit Message
907
908
git show -s COMMIT_ID
909
910
911
…is
912
913
fossil time -n 1 COMMIT_ID
914
915
…or with a shorter, more obvious command, though with more verbose output:
916
917
fossil info COMMIT_ID
918
919
The `fossil info` command isn’t otherwise a good equivalent to
920
`git show`; it just overlaps its functionality in some areas. Much of
921
what’s missing is present in the corresponding [`/info` web
922
view][infow], though.
923
924
925
#### <a id="dstat"></a> Diff Statistics
926
927
Fossil’s closest internal equivalent to commands like
928
`git show --stat` is:
929
930
fossil diff -i --from 2020-04-01 --numstat
931
932
The `--numstat` output is a bit cryptic, so we recommend delegating
933
this task to [the widely-available `diffstat` tool][dst], which gives
934
a histogram in its default output mode rather than bare integers:
935
936
fossil diff -i -v --from 2020-04-01 | diffstat
937
938
We gave the `-i` flag in both cases to force Fossil to use its internal
939
diff implementation, bypassing [your local `diff-command` setting][dcset]
940
since the `--numstat` option has no effect when you have an external diff
941
command set.
942
943
If you leave off the `-v` flag in the second example, the `diffstat`
944
output won’t include info about any newly-added files.
945
946
[dcset]: https://fossil-scm.org/home/help/diff-command
947
[dst]: https://invisible-island.net/diffstat/diffstat.html
948
949
950
<a id="btnames"></a>
951
## Branch and Tag Names
952
953
Fossil has no special restrictions on the names of tags and branches,
954
though you might want to keep [Git's tag and branch name restrictions][gcrf]
955
in mind if you plan on [mirroring your Fossil repository to GitHub][mirgh].
956
957
Fossil does not require tag and branch names to be unique. It is
958
common, for example, to put a “`release`” tag on every release for a
959
Fossil-hosted project. This does not create a conflict in Fossil, since
960
Fossil resolves the ambiguity in a predictable way: the newest match
961
wins. Therefore, “`fossil up release`” always gets you the current
962
release in a project that uses this tagging convention.
963
964
[The `fossil git export` command][fge] squashes repeated tags down to a
965
single instance to avoid confusing Git, exporting only the newest tag,
966
emulating Fossil’s own ambiguity resolution rule as best it can within
967
Git’s limitations.
968
969
[fge]: /help/git
970
[gcrf]: https://git-scm.com/docs/git-check-ref-format
971
972
973
974
975
<a id="cpickrev"></a>
976
## Cherry-Picking and Reverting Commits
977
978
Git’s separate "`git cherry-pick`" and “`git revert`” commands are
979
options to the [`fossil merge` command][merge]: `--cherrypick` and
980
`--backout`, respectively. We view this as sensible, since these are
981
both merge operations, and the two actions differ only in direction.
982
983
Unlike in Git, the Fossil file format remembers cherrypicks and backouts
984
and can later show them as dashed lines on the graphical timeline.
985
986
[merge]: /help/merge
987
988
989
990
<a id="mvrm"></a>
991
## File Moves and Renames Are Soft by Default
992
993
The "[`fossil mv`][mv]" and "[`fossil rm`][rm]" commands work like they
994
do in CVS in that they schedule the changes for the next commit by
995
default: they do not actually rename or delete the files in your
996
check-out.
997
998
If you don’t like that default, you can change it globally:
999
1000
fossil setting --global mv-rm-files 1
1001
1002
Now these commands behave like in Git in any Fossil repository where
1003
this setting hasn’t been overridden locally.
1004
1005
If you want to keep Fossil’s soft `mv/rm` behavior most of the time, you
1006
can cast it away on a per-command basis:
1007
1008
fossil mv --hard old-name new-name
1009
1010
[mv]: /help/mv
1011
[rm]: /help/rm
1012
1013
1014
----
1015
1016
1017
## <a id="cvdate" name="cs1"></a> Case Study 1: Checking Out a Version by Date
1018
1019
Let’s get into something a bit more complicated: a case study showing
1020
how the concepts lined out above cause Fossil to materially differ in
1021
day-to-day operation from Git.
1022
1023
Why would you want to check out a version of a project by date? Perhaps
1024
your customer gave you a vague bug report referencing only a
1025
date rather than a version. Or, you may be poking semi-randomly through
1026
history to find a “good” version to anchor the start point of a
1027
[`fossil bisect`][fbis] operation.
1028
1029
My search engine’s first result for “git checkout by date” is [this
1030
highly-upvoted accepted Stack Overflow answer][gcod]. The first command
1031
it gives is based on Git’s [`rev-parse` feature][grp]:
1032
1033
git checkout master@{2020-03-17}
1034
1035
There are a number of weaknesses in this command. From least to most
1036
critical:
1037
1038
1. It’s a bit cryptic. Leave off the refname or punctuation, and it
1039
means something else. You cannot simplify the cryptic incantation in
1040
the typical use case.
1041
1042
2. A date string in Git without a time will be interpreted as
1043
“[at the local wall clock time on the given date][gapxd],” so the
1044
command means something different from one second to the next! This
1045
can be a serious problem if there are multiple commits on that date, because
1046
the command will give different results depending on the time of
1047
day you run it.
1048
1049
3. It gives misleading output if there is no close match for the date
1050
in the local [reflog]. It starts out empty after a fresh clone, and
1051
while it does build up as you use that clone, Git [automatically
1052
prunes][gle] the reflog to 90 days of history by default. This means
1053
the command above can give different results from one machine to the
1054
next, or even from one day to the next on the same clone.
1055
1056
The command won’t fail outright if the reflog can’t resolve the
1057
given date: it simply gives the closest commit it can come up with,
1058
even if it’s months or years out from your target! Sometimes it
1059
gives a warning about the reflog not going back far enough to give a
1060
useful result, and sometimes it doesn’t. If you’re on a fresh clone,
1061
you are likely to get the “tip” commit’s revision ID no matter what
1062
date value you give.
1063
1064
Git tries its best, but because it’s working from a purgeable and
1065
possibly-stale local cache, you cannot trust its results.
1066
1067
Consequently, we cannot recommend this command at all. It’s unreliable even in the
1068
best case.
1069
1070
That same Stack Overflow answer therefore goes on to recommend an
1071
entirely different command:
1072
1073
git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)
1074
1075
We believe you get such answers to Git help requests in part
1076
because of its lack of an always-up-to-date [index into its log](#log) and in
1077
part because of its “small tools loosely joined” design philosophy. This
1078
sort of command is therefore composed piece by piece:
1079
1080
<p style="text-align:center">◆  ◆  ◆</p>
1081
1082
“Oh, I know, I’ll search the rev-list, which outputs commit IDs by
1083
parsing the log backwards from `HEAD`! Easy!”
1084
1085
git rev-list --before=2020-03-17
1086
1087
“Blast! Forgot the commit ID!”
1088
1089
git rev-list --before=2020-03-17 master
1090
1091
“Double blast! It just spammed my terminal with revision IDs! I need to
1092
limit it to the single closest match:
1093
1094
git rev-list -n 1 --before=2020-03-17 master
1095
1096
“Okay, it gives me a single revision ID now, but is it what I’m after?
1097
Let’s take a look…”
1098
1099
git show $(git rev-list -n 1 --before=2020-03-17 master)
1100
1101
“Oops, that’s giving me a merge commit, not what I want.
1102
Off to search the web… Okay, it says I need to give either the
1103
`--first-parent` or `--no-merges` flag to show only regular commits,
1104
not merge-commits. Let’s try the first one:”
1105
1106
git show $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
1107
1108
“Better. Let’s check it out:”
1109
1110
git checkout $(git rev-list -n 1 --first-parent --before=2020-03-17 master)
1111
1112
“Success, I guess?”
1113
1114
<p style="text-align:center">◆  ◆  ◆</p>
1115
1116
This vignette is meant to explain some of Git’s popularity: it rewards
1117
the sort of people who enjoy puzzles, many of whom are software
1118
developers and thus need a tool like Git. Too bad if you’re just a
1119
normal user.
1120
1121
And too bad if you’re a Windows user who doesn’t want to use [Git
1122
Bash][gbash], since neither of the stock OS command shells have a
1123
command interpolation feature needed to run that horrid command.
1124
1125
This alternative command still has weakness #2 above: if you run the
1126
second `git show` command above on [Git’s own repository][gitgh], your
1127
results may vary because there were four non-merge commits to Git on the
1128
17th of March, 2020.
1129
1130
You may be asking with an exasperated huff, “What is your *point*, man?”
1131
The point is that the equivalent in Fossil is simply:
1132
1133
fossil up 2020-03-17
1134
1135
…which will *always* give the commit closest to midnight UTC on the 17th
1136
of March, 2020, no matter whether you do it on a fresh clone or a stale
1137
one. The answer won’t shift about from one clone to the next or from
1138
one local time of day to the next. We owe this reliability and stability
1139
to three Fossil design choices:
1140
1141
* Parse timestamps from all commits on clone into a local commit index,
1142
then maintain that index through subsequent commits and syncs.
1143
1144
* Use an indexed SQL `ORDER BY` query to match timestamps to commit
1145
IDs for a fast and consistent result.
1146
1147
* Round incomplete timestamp strings up using [rules][frud] consistent across
1148
computers and local time of day.
1149
1150
[frud]: https://fossil-scm.org/home/file/src/name.c?ci=d2a59b03727bc3&ln=122-141
1151
[gbash]: https://appuals.com/what-is-git-bash/
1152
[gapxd]: https://github.com/git/git/blob/7f7ebe054a/date.c#L1298-L1300
1153
[gcod]: https://stackoverflow.com/a/6990682/142454
1154
[gdh]: https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit/
1155
[gitgh]: https://github.com/git/git/
1156
[gle]: https://git-scm.com/docs/git-reflog#_options_for_expire
1157
[gmc]: https://github.com/git/git/commit/67b0a24910fbb23c8f5e7a2c61c339818bc68296
1158
[grp]: https://git-scm.com/docs/git-rev-parse
1159
[reflog]: https://git-scm.com/docs/git-reflog
1160
1161
----
1162
1163
## <a id="morigin" name="cs2"></a> Case Study 2: Multiple "origin" Servers
1164
1165
Now let us consider a common use case at the time of this writing — during the
1166
COVID-19 pandemic — where you’re working from home a lot, going into the
1167
office one part-day a week only to do things that have to be done
1168
on-site at the office. Let us also say you have no remote
1169
access back into the work LAN, such as because your site IT is paranoid
1170
about security. You may still want off-machine backups of your commits
1171
while working from home,
1172
so you need the ability to quickly switch between the “home” and
1173
“work” remote repositories, with your laptop acting as a kind of
1174
[sneakernet][sn] link between the big development server at the office
1175
and your family’s home NAS.
1176
1177
#### Git Method
1178
1179
We first need to clone the work repo down to our laptop, so we can work on it
1180
at home:
1181
1182
git clone https://dev-server.example.com/repo
1183
cd repo
1184
git remote rename origin work
1185
1186
The last command is optional, strictly speaking. We could continue to
1187
use Git’s default name for the work repo’s origin — sensibly enough
1188
called “`origin`” — but it makes later commands harder to understand, so
1189
we rename it here. This will also make the parallel with Fossil easier
1190
to draw.
1191
1192
The first time we go home after this, we have to reverse-clone the work
1193
repo up to the NAS:
1194
1195
ssh my-nas.local 'git init --bare /SHARES/dayjob/repo.git'
1196
git push --all ssh://my-nas.local//SHARES/dayjob/repo.git
1197
1198
Realize that this is carefully optimized down to these two long
1199
commands. In practice, we’d expect a user typing these commands by hand from memory
1200
to need to give four or more commands here instead.
1201
Packing the “`git init`” call into the “`ssh`” call is something more
1202
often done in scripts and documentation examples than done interactively,
1203
which then necessitates a third command before the push, “`exit`”.
1204
There’s also a good chance that you’ll forget the need for the `--bare`
1205
option here to avoid a fatal complaint from Git that the laptop can’t
1206
push into a non-empty repo. If you fall into this trap, among the many
1207
that Git lays for newbies, you have to nuke the incorrectly initted
1208
repo, search the web or Git man pages to find out about `--bare`, and try again.
1209
1210
Having navigated that little minefield,
1211
we can tell Git that there is a second origin, a “home” repo in
1212
addition to the named “work” repo we set up earlier:
1213
1214
git remote add home ssh://my-nas.local//SHARES/dayjob/repo.git
1215
git config master.remote home
1216
1217
We don’t have to push or pull because the remote repo is a complete
1218
clone of the repo on the laptop at this point, so we can just get to
1219
work now, committing along the way to get our work safely off-machine
1220
and onto our home NAS, like so:
1221
1222
git add
1223
git commit
1224
git push
1225
1226
We didn’t need to give a remote name on the push because we told it the
1227
new upstream is the home NAS earlier.
1228
1229
Now Friday comes along, and one of your office-mates needs a feature
1230
you’re working on. You agree to come into the office later that
1231
afternoon to sync up via the dev server:
1232
1233
git push work master # send your changes from home up
1234
git pull work master # get your coworkers’ changes
1235
1236
Alternately, we could add “`--set-upstream/-u work`” to the first
1237
command if we were coming into work long enough to do several Git-based things, not just pop in and sync.
1238
That would allow the second to be just “`git pull`”, but the cost is
1239
that when returning home, you’d have to manually reset the upstream
1240
again.
1241
1242
This example also shows a consequence of that fact that
1243
[Git doesn’t sync branch names](#syncall): you have to keep repeating
1244
yourself like an obsequious supplicant: “Master, master.” Didn’t we
1245
invent computers to serve humans, rather than the other way around?
1246
1247
1248
#### Fossil Method
1249
1250
Now we’re going to do the same thing using Fossil, with
1251
the commands arranged in blocks corresponding to those above for comparison.
1252
1253
We start the same way, cloning the work repo down to the laptop:
1254
1255
fossil clone https://dev-server.example.com/repo
1256
cd repo
1257
fossil remote add work https://dev-server.example.com/repo
1258
1259
We’ve chosen the new “`fossil clone URI`” syntax rather than separate
1260
`clone` and `open` commands to make the parallel with Git clearer. [See
1261
above](#mwd) for more on that topic.
1262
1263
Our [`remote` command][rem] is longer than the Git equivalent because
1264
Fossil currently has no short command
1265
to rename an existing remote. Worse, unlike with Git, we can’t just keep
1266
using the default remote name because Fossil uses that slot in its
1267
configuration database to store the *current* remote name, so on
1268
switching from work to home, the home URL will overwrite the work URL if
1269
we don’t give it an explicit name first.
1270
1271
Although the Fossil commands are longer, so far, keep it in perspective:
1272
they’re one-time setup costs,
1273
easily amortized to insignificance by the shorter day-to-day commands
1274
below.
1275
1276
On first beginning to work from home, we reverse-clone the Fossil repo
1277
up to the NAS:
1278
1279
rsync repo.fossil my-nas.local:/SHARES/dayjob/
1280
1281
Now we’re beginning to see the advantage of Fossil’s simpler model,
1282
relative to the tricky “`git init && git push`” sequence above.
1283
Fossil’s alternative is almost impossible to get
1284
wrong: copy this to that. *Done.*
1285
1286
We’re relying on the `rsync` feature that creates up to one level of
1287
missing directory (here, `dayjob/`) on the remote. If you know in
1288
advance that the remote directory already exists, you could use a
1289
slightly shorter `scp` command instead. Even with the extra 2 characters
1290
in the `rsync` form, it’s much shorter because a Fossil repository is a
1291
single SQLite database file, not a tree containing a pile of assorted
1292
files. Because of this, it works reliably without any of [the caveats
1293
inherent in using `rsync` to clone a Git repo][grsync].
1294
1295
Now we set up the second remote, which is again simpler in the Fossil
1296
case:
1297
1298
fossil remote add home ssh://my-nas.local//SHARES/dayjob/repo.fossil
1299
fossil remote home
1300
1301
The first command is nearly identical to the Git version, but the second
1302
is considerably simpler. And to be fair, you won’t find the
1303
“`git config`” command above in all Git tutorials. The more common
1304
alternative we found with web searches is even longer:
1305
“`git push --set-upstream home master`”.
1306
1307
Where Fossil really wins is in the next step, making the initial commit
1308
from home:
1309
1310
fossil ci
1311
1312
It’s one short command for Fossil instead of three for Git — or two if
1313
you abbreviate it as “`git commit -a && git push`” — because of Fossil’s
1314
[autosync] feature and deliberate omission of a
1315
[staging feature](#staging).
1316
1317
The “Friday afternoon sync-up” case is simpler, too:
1318
1319
fossil remote work
1320
fossil sync
1321
1322
Back at home, it’s simpler still: we may be able to do away with the second command,
1323
saying just “`fossil remote home`” because the sync will happen as part
1324
of the next commit, thanks once again to Fossil’s autosync feature. If
1325
the working branch now has commits from other developers after syncing
1326
with the central repository, though, you’ll want to say “`fossil up`” to
1327
avoid creating an inadvertent fork in the branch.
1328
1329
(Which is easy to fix if it occurs: `fossil merge` without arguments
1330
means “merge open tips on the current branch.”)
1331
1332
[grsync]: https://stackoverflow.com/q/1398018/142454
1333
[qs]: ./quickstart.wiki
1334
[shwmd]: ./fossil-v-git.wiki#checkouts
1335
[sn]: https://en.wikipedia.org/wiki/Sneakernet
1336

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button