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