Diff between two different check-outs, both with edits
(1) By Richard Hipp (drh) on 2024-12-13 17:49:15 [link] [source]
I have a need to be able to easily compute a diff between two Fossil check-outs, each containing uncommitted edits, originating from the same repository, though with each check-out probably being based off of a different check-in. To illustrate:
- CD to ~/workdir1
fossil up trunk
- Make some edits.
- CD to ~/workdir2
fossil up branch1
← same repo, different check-in- Make different edits.
- Compare all managed files in ~/workdir1 and ~/workdir2 ← This is what I need to be able to do
Fossil cannot currently do this. At this moment, Fossil is able to do a diff between a modified check-out and any arbitrary check-in, but it cannot do a diff between two different modified check-outs.
I'll be working to fill in this capability gap. The purpose of this post is simply to give notice of my intentions. You are welcomed to provide advice about appropriate syntax or operation of this new capability if you like.
(2.4) By andygoth on 2024-12-14 06:43:16 edited from 2.3 in reply to 1 [link] [source]
To get what you're asking for, in the past I've diff'ed Fossil's diffs. (I've also diff'ed the outputs of fossil changes
or fossil changes -differ
, then diff'ed the diffs for only files of interest.) The output is quite challenging to read and conceptualize because it has two columns of +
's and -
's, but it shows if and where changes diverge.
The first step to documenting and understanding the output of such a meta-diff is to try every possible combination of operations spanning two checkouts:
sh -x <<EOT
alias f=fossil
rm -rf test.fossil workdir{1,2}{,.diff}
f new test.fossil
f open test.fossil -workdir workdir1
cat > workdir1/file <<EOF
4 | Keep | Absent
5 | Keep | Keep
6 | Keep | Remove
7 | Keep | Insert
8 | Remove | Absent
9 | Remove | Keep
A | Remove | Remove
B | Remove | Insert
EOF
f add -chdir workdir1 file
f commit -chdir workdir1 -tag version1 -m version1
cat > workdir1/file <<EOF
1 | Absent | Keep
2 | Absent | Remove
5 | Keep | Keep
6 | Keep | Remove
9 | Remove | Keep
A | Remove | Remove
D | Insert | Keep
E | Insert | Remove
EOF
f changes -chdir workdir1 -hash
f commit -chdir workdir1 -tag version2 -m version2 -allow-empty
f checkout -chdir workdir1 version1
f open -workdir workdir2 test.fossil version2
cat > workdir1/file <<EOF
4 | Keep | Absent
5 | Keep | Keep
6 | Keep | Remove
7 | Keep | Insert
C | Insert | Absent
D | Insert | Keep
E | Insert | Remove
F | Insert | Insert
EOF
cat > workdir2/file <<EOF
1 | Absent | Keep
3 | Absent | Insert
5 | Keep | Keep
7 | Keep | Insert
9 | Remove | Keep
B | Remove | Insert
D | Insert | Keep
F | Insert | Insert
EOF
f changes -chdir workdir1 -hash
f changes -chdir workdir2 -hash
f diff -chdir workdir1 > workdir1.diff
f diff -chdir workdir2 > workdir2.diff
diff -u workdir1.diff workdir2.diff
EOT
This outputs:
--- workdir1.diff 2024-12-13 21:10:26.092141758 -0600
+++ workdir2.diff 2024-12-13 21:10:26.246141761 -0600
@@ -3,16 +3,16 @@
--- file
+++ file
@@ -1,8 +1,8 @@
- 4 | Keep | Absent
+ 1 | Absent | Keep
+-2 | Absent | Remove
++3 | Absent | Insert
5 | Keep | Keep
- 6 | Keep | Remove
- 7 | Keep | Insert
--8 | Remove | Absent
--9 | Remove | Keep
+-6 | Keep | Remove
++7 | Keep | Insert
+ 9 | Remove | Keep
-A | Remove | Remove
--B | Remove | Insert
-+C | Insert | Absent
-+D | Insert | Keep
-+E | Insert | Remove
++B | Remove | Insert
+ D | Insert | Keep
+-E | Insert | Remove
+F | Insert | Insert
Let's try to make sense of this, though to keep this somewhat tractable, we'll ignore line numbers. There are four possible operations within a single checkout:
Operation | Description |
---|---|
Absent | Present in neither version |
Keep | Present in both versions |
Remove | Present only in old version |
Insert | Present only in new version |
Except for Absent/Absent, the "square" of the operation table (cross with itself) spans all fifteen possible combinations of operations that may occur when comparing two diffs. A table will be given below.
Each of these fifteen possibilities is indicated in the diff by either one or two lines of text. Each line begins with a two-character code. The codes comprise all combinations of space, -
, and +
, therefore we have nine codes. Six codes are always single-line, whereas the remaining three codes permit (but do not require) a second line. The six single-line codes map directly to six of the possible operation combinations, and the three multi-line codes indirectly map to the remaining nine operation combinations.
The single-line codes begin with space or +
.
The multi-line codes begin with -
. If there is a second line, its code begins with +
, and the two codes end with different characters.
It is ambiguous whether a code beginning with +
indicates a single-line operation or is the second line of a two-line operation. To resolve the ambiguity, for each line starting with -
, look ahead for the immediately following block of lines beginning with +
and hunt for a line with identical contents, differing only in the code. If found, that's the second line. If not, it's a single-line operation.
Single- and multi-line codes and ambiguous cases are nothing new; they're just how diff works. Modifying a line is classically shown as a remove followed by an insert, thus modifying a line is a two-line code made up of two one-line codes. The distinction between modification versus removal plus insertion is a matter of interpretation, not a matter of definition.
This table summarizes the possibilities. Due to formatting restrictions, it displays space as s
:
Code 1 | Code 2 | Operation 1 | Operation 2 | Before 1 | Before 2 | After 1 | After 2 |
---|---|---|---|---|---|---|---|
ss |
None | Keep | Keep | ✔ | ✔ | ✔ | ✔ |
s- |
None | Remove | Remove | ✔ | ✔ | ||
s+ |
None | Insert | Insert | ✔ | ✔ | ||
-s |
None | Keep | Absent | ✔ | ✔ | ||
-s |
+- |
Keep | Remove | ✔ | ✔ | ✔ | |
-s |
++ |
Keep | Insert | ✔ | ✔ | ✔ | |
-- |
None | Remove | Absent | ✔ | |||
-- |
+s |
Remove | Keep | ✔ | ✔ | ✔ | |
-- |
++ |
Remove | Insert | ✔ | ✔ | ||
-+ |
None | Insert | Absent | ✔ | |||
-+ |
+s |
Insert | Keep | ✔ | ✔ | ✔ | |
-+ |
+- |
Insert | Remove | ✔ | ✔ | ||
+s |
None | Absent | Keep | ✔ | ✔ | ||
+- |
None | Absent | Remove | ✔ | |||
++ |
None | Absent | Insert | ✔ |
I think you'll agree this is very complicated and too much to display in the end product, so please accept it as merely an interim stage of theory development. I'm going through it all to explore the complexity of the domain and to show how to implement (or approximate) it with the tools we have right now. The next step is to think about where we want to go with this.
One step toward simplification is to flatten multi-line codes into single-line codes. Let's introduce a fourth character, =
, denoting "keep," whereas space denotes "absent." Recasting the above table, we'd have:
Code | Operation 1 | Operation 2 | Old Code(s) |
---|---|---|---|
s= |
Absent | Keep | +s |
s- |
Absent | Remove | +- |
s+ |
Absent | Insert | ++ |
=s |
Keep | Absent | -s |
== |
Keep | Keep | ss |
=- |
Keep | Remove | -s+- |
=+ |
Keep | Insert | -s++ |
-s |
Remove | Absent | -- |
-= |
Remove | Keep | --+s |
-- |
Remove | Remove | s- |
-+ |
Remove | Insert | --++ |
+s |
Insert | Absent | -+ |
+= |
Insert | Keep | -++s |
+- |
Insert | Remove | -++- |
++ |
Insert | Insert | s+ |
Even with this simplification, we're still too complicated. You are asking for the differences in changes, independent of baselines. The next simplification is to filter out some codes: s=
=s
==
--
++
. These represent either no change being made, or the same change being made. We'd be left with ten out of the original fifteen combinations. Next, conflate absent with keep, i.e., turn =
into space. At the cost of ambiguity, that drops us to six combinations, an acceptable number. (Maybe a -complex
or -complete
option could enable these more complicated, less useful codes, in case someone needs them.) This next table will show "None" in place of either "Absent" or "Keep" to denote that no change is being made, without claiming if the line was part of the baseline or not:
Code | Operation 1 | Operation 2 | Old Code(s) |
---|---|---|---|
s- |
None | Remove | +- , -s+- |
s+ |
None | Insert | ++ , -s++ |
-s |
Remove | None | -- , --+s |
-+ |
Remove | Insert | --++ |
+s |
Insert | None | -+ , -++s |
+- |
Insert | Remove | -++- |
None | None | None | ss , +s , -s |
None | Remove | Remove | s- |
None | Insert | Insert | s+ |
What ambiguity does this incur? Well, there's no way to show context anymore, because it's unclear whether the context lines would come from the baseline or checkout versions of the first or the second file. Similarly, the line numbers won't make any sense either. Restating the above paragraph, there would be no distinction between lines being in one file's baseline or not, aside from -+
and +-
which don't say "None" in the table.
To make this concrete, the final diff might say:
--- workdir1/file 2024-12-13 21:10:26.092141758 -0600
+++ workdir2/file 2024-12-13 21:10:26.246141761 -0600
-2 | Absent | Remove
+3 | Absent | Insert
-6 | Keep | Remove
+7 | Keep | Insert
- 8 | Remove | Absent
- 9 | Remove | Keep
-+B | Remove | Insert
+ C | Insert | Absent
+ D | Insert | Keep
+-E | Insert | Remove
This, at last, is a diff-like report that clearly shows only the differences between the changes in two checkouts, regardless of their baselines. I algorithmically produced it by taking the original diff, identifying each change's one or two codes, looking them up in the "Old Code(s)" column of the above table, and replacing the code with the one in the leftmost column. For two-line codes, I dropped the second line. I also dropped lines whose new code is listed as "None."
Timestamps and filenames shown in this report are those of the checkout files. Since it cannot be compatible with diff anyway (no context, no line numbers, no way to apply as a patch), maybe the report could be extended to identify each file's baseline hashes, perhaps also each checkout's baseline commit hash, or even the original filenames in the event of a rename. Could even show type changes between regular/executable/symlink.
Now, a word about command syntax. The fossil diff
command could be extended to support this mode when given exactly two filename or directory arguments, and those names are in different checkouts. In this case, it would not complain about the current directory not being in a checkout. It would also forbid many options, likely: -branch
, -checkin
, -from
, -linenum
, -numstat
, -to
, -undo
. The -brief
option would list files whose changes differ between the two checkouts. -side-by-side
might be interesting if it showed the two context diffs side-by-side. Alternately, add an option enabling this new mode: -metadiff
. Most likely it would be less confusing to implement and document for this to be an altogether new command: fossil metadiff
.
One more thing I'd like to add. I think this could be useful not only for comparing two checkouts' changes, but also for evaluating/auditing an already-committed merge. A four-way diff, I suppose. Starting with commit A1, you make changes and arrive at commit A2, but over on a different branch someone merges your changes on top of commit B1 to get B2. Later on, you want to see what all it took to accomplish the merge, also check for surprises. If the merge was perfectly clean (basically nothing but {UPDATED,ADDED}_BY_{MERGE,INTEGRATE}), then the meta-diff of A1/A2 versus B1/B2 would be empty. If the merge involved some conflict resolution (EDITED), then the meta-diff would show only said conflict resolution. If the merge snuck in some ancillary changes, inadvertently or otherwise, those would show up as well.
(3) By Richard Hipp (drh) on 2024-12-14 11:38:04 in reply to 1 [link] [source]
Proposed new command-line syntax is two extra options for the "fossil diff" command:
--from-ckout
PATH → Path to the root of some other checkout that will be the "from" side of the diff.--to-ckout
PATH → Path to the root of another checkout that is the "to" side of the diff.
You can specify one or the other of these. If you use them both, then one or the other just refer to the root of the current working check-out. Thus if you have two working check-outs in sibling directories "wd1" and "wd2", with wd1 on trunk and wd2 on a branch and both have uncommitted changes, if you are currently at the root of wd1, you can type:
fossil diff --tk --to-ckout ../wd2
And you will see the differences going from the current edited state of the wd1 checkout over to the current edited state of the wd2 checkout. The previous command means exactly the same thing as:
fossil diff --tk --to-ckout ../wd2 --from-ckout .
It is usually the case that if you do not otherwise specify the "to" side
of a diff, then it defaults to "--to-ckout .
" In other words, the usual
result of a diff shows the uncommitted changes of your working check-out on
the right-hand side. (One exception is with the --branch option.) The new
command-line syntax simply allows you to specify the uncommitted changes of
some other working check-out on either the left or the right side.
Any other check-out specified using either --from-ckout or --to-ckout must be for the exact same repository file as the working check-out.
(4.1) By Richard Hipp (drh) on 2024-12-14 20:09:57 edited from 4.0 in reply to 1 [link] [source]
New Approach: Simpler, Lower Risk
fossil diff --tree ../wd2
The command above uses whatever files it finds in the ../wd2 as the baseline for comparison to managed files in the working check-out. The ../wd2 directory need not be another check-out; it might be a copy of the source tree obtained from a tarball, or a Git checkout of a Git clone of the repository, or similar.
The algorithm is simple:
- Look at each managed file in the working check-out.
- Compare each managed file against the file with the same name over at ../wd2 and write out any differences.
(Edit): I'm not sure "--tree" is the right option name though. Maybe something like "--foreign-baseline". It need not be a compact option name, as it seems unlikely to be used all that often. I'm open to suggestions.
(5.1) By spindrift on 2024-12-14 20:24:03 edited from 5.0 in reply to 4.1 [link] [source]
I like this version.
fossil diff --alt-root ../wd2
or
fossil diff --variant ../wd2
Perhaps?
(6) By anonymous on 2024-12-14 22:31:45 in reply to 4.1 [link] [source]
The already existing --to
would seem to fit the need.
fossil diff --to ./path-name # eg. "../other-dir"
fossil diff --to branch-name # eg. "trunk"
fossil diff --to hash_prefix # eg. "13579bdf"
(9) By Warren Young (wyoung) on 2024-12-15 01:06:08 in reply to 6 [link] [source]
Yes; also -from
. Detecting whether the argument is a path vs a Fossil NAME is trivial, and it keeps the number of distinct concepts from ballooning.
(10) By Martin Gagnon (mgagnon) on 2024-12-15 01:11:37 in reply to 9 [link] [source]
But I guess there might be some case where a directory name can be the same as a branch name or a tag name.
I know it is rare, but it can cause some confusion when it happens.
(11.1) By spindrift on 2024-12-15 07:51:11 edited from 11.0 in reply to 10 [link] [source]
Fossil already allows specification of the type of reference one is using. And even specifically gives examples of using this type of addressing with the diff command.
fossil diff --from root:xyzzy --to xyzzy
How about:
fossil diff --from file:../foo/
Or
fossil diff --from co:~/bar --to co:checkouts/build
Then it's just another specifier. And you could put the second checkout directory on the left or the right, using whatever current directory you wanted...
(14) By Warren Young (wyoung) on 2024-12-15 11:45:24 in reply to 11.1 [link] [source]
This is all fine, except that no shell I tried1 will do tilde expansion within an argument, only at the beginning. Thus, your co:~/bar
always gets treated literally. You'd have to use an environment variable to get the reference to work as expected: co:$HOME/bar
.
Also, if we ever do decide we need the tags, I think it would be more consistent to use ckout:
than co:
.
This said, I'm with drh in #12: no tags, just raw paths. There won't be conflicts unless someone is going out of their way to create them.
- ^
Current zsh on macOS, old Bash 3.2 on same, real AT&T ksh93u+, and the ksh88 clone that typically implements
/bin/sh
in Busybox, via Alpine.
(13) By Warren Young (wyoung) on 2024-12-15 11:40:13 in reply to 10 [link] [source]
I know it is rare
Given that the typical use case will have the path referenced relative to the CWD, I'd have to say it's rare unto nonexistence. Who is going to name their branch ../release
or similar?
This concern is inventing future conflicts where none currently exist.
(16) By Martin Gagnon (mgagnon) on 2024-12-15 17:45:08 in reply to 13 [link] [source]
Yeah, I didn’t think about the fact this must be called from a checkout, so the “../“ is kind of mandatory and almost guarantee there will be no clash with fossil names.
(17) By Warren Young (wyoung) on 2024-12-15 18:52:41 in reply to 16 [link] [source]
Even if you follow the pattern that branch name = directory name, you can disambiguate it as --from ./release
and such.
(7) By anonymous on 2024-12-14 23:15:04 in reply to 4.1 [link] [source]
fossil diff --path ../foo
(8) By Stephan Beal (stephan) on 2024-12-14 23:20:18 in reply to 4.1 [link] [source]
(Edit): I'm not sure "--tree" is the right option name though. Maybe something like "--foreign-baseline". It need not be a compact option name, as it seems unlikely to be used all that often. I'm open to suggestions.
fossil diff --ext|external /foo
fossil diff --against /bar
(12) By Richard Hipp (drh) on 2024-12-15 11:13:20 in reply to 8 [link] [source]
FWIW, current trunk check-in supports "--external-baseline
PATH", which is a
bit wordy, but seems clear enough.
As I type this, I'm rethinking the use of "--from
PATH" with no prefix or any
other marking on PATH. If I go that route, the rule would be:
If PATH is a tag (or branch name) that identifies a check-in, then use the identified check-in as the baseline.
Else if PATH is a valid pathname to a directory that exists, then use the files in that directory as the baseline.
Otherwise, raise an error.
I had originally rejected that idea as it overloads the semantics of the argument to --from. But this morning, that doesn't seem so bad. Perhaps I'll change it (tomorrow).
(15.2) By Richard Hipp (drh) on 2024-12-15 16:55:53 edited from 15.1 in reply to 1 [link] [source]
As of the latest trunk check-ins, the --from syntax suggested above is used. You can type:
fossil diff --from ../otherckout
And the difference will be between the files in ../otherckout and in your working checkout. This also works with the "ui" command:
fossil ui --from ../otherckout
For the "ui" command, the argument to --from must be a directory. Fossil determines that the argument is a directory by the presence of one or more directory separator characters. Specifically it uses code like this:
if( zFrom != fossil_tail(zFrom) ){...}
In the case of the "diff" command, it also requires that the directory exist and that there not be a tag by the same name. Those additional constraints are not enforced with the "ui" command, because they are quite difficult to enforce for remote systems.
At this time, I consider development on this enhancement to be complete, or at least sufficiently complete to solve my problem. Thanks, y'all, for your help and suggestions. I think the result turned out well.
(18) By Doug (doug9forester) on 2024-12-16 21:02:36 in reply to 15.2 [link] [source]
fossil ui not working for trunk - works for fossil 2.24.
On windows 11, cyg:
dougf@HPDesktop:~/.../trunk/email_blasts$ fossil version
This is fossil version 2.24 [8be0372c10] 2024-04-23 13:25:26 UTC
dougf@HPDesktop:~/.../trunk/email_blasts$ fossil ui
Temporary files: C:\cygwin64\tmp\fossil\fossil_server_P8084*
Listening for HTTP requests on TCP port 8084
Launch webbrowser: start "" "http://localhost:8084/timeline?c=current" &
Type Ctrl-C to stop the HTTP server
dougf@HPDesktop:~/.../trunk/email_blasts$ fossil_trunk_241216_1335 version
This is fossil version 2.26 [bdc6bb1cfb] 2024-12-16 16:22:39 UTC
dougf@HPDesktop:~/.../trunk/email_blasts$ fossil_trunk_241216_1335 ui
Listening for HTTP requests on TCP port 8084
------------- 2024-12-16 21:01:21 UTC ------------
warning: cannot start browser
while in ui
(19) By Richard Hipp (drh) on 2024-12-16 21:12:50 in reply to 18 [link] [source]
Works for me in Win11.
I'm not running Cygwin. If you want Fossil to work with Cygwin, please suggest
patches. A good start would be to bisect and show us which 143 check-ins in
between trunk and the previous release broke it for you. The output from
running "fossil ui --systemtrace
" might also give clues.
(20) By Daniel Dumitriu (danield) on 2024-12-16 21:17:39 in reply to 19 [link] [source]
Same here on first two counts, and Win10 on top.
The good news is, you'd need to test at most eight check-ins to pinpoint the culprit ;)
(21) By Doug (doug9forester) on 2024-12-16 21:25:24 in reply to 20 [link] [source]
Which is: ...?
(22) By Doug (doug9forester) on 2024-12-16 21:26:56 in reply to 19 [link] [source]
Oh. 8 bisects. How do you do bisects?
(24) By Doug (doug9forester) on 2024-12-17 01:48:56 in reply to 19 [link] [source]
So the bad news is that when I build 2.24 on win11 cyg, the call to ui fails. When I use the downloaded 2.24 executable, it works. I ran the bisects all the way assuming the 2.24 I built was good. it wasn't:
First, the downloaded executable:
dougf@HPDesktop:~/fossil$ which fossil
/cygdrive/c/DougsTools/fossil
dougf@HPDesktop:~/fossil$ ls -al /cygdrive/c/DougsTools/fossil
-rwxrwx---+ 1 dougf dougf 10290176 Dec 16 13:48 /cygdrive/c/DougsTools/fossil
dougf@HPDesktop:~/fossil$ fossil version
This is fossil version 2.24 [8be0372c10] 2024-04-23 13:25:26 UTC
dougf@HPDesktop:~/fossil$ fossil ui &
[2] 11356
Temporary files: C:\cygwin64\tmp\fossil\fossil_server_P8092*
Listening for HTTP requests on TCP port 8092
Launch webbrowser: start "" "http://localhost:8092/timeline?c=current" &
Type Ctrl-C to stop the HTTP server
Then the executable I built with 'make clean reconfig; make':
dougf@HPDesktop:~/fossil$ ls -al ./fossil.exe
-rwxr-xr-x+ 1 dougf dougf 17435496 Dec 16 18:14 ./fossil.exe
dougf@HPDesktop:~/fossil$ ./fossil.exe version
This is fossil version 2.24 [8be0372c10] 2024-04-23 13:25:26 UTC
dougf@HPDesktop:~/fossil$ ./fossil.exe ui &
[11] 11350
Listening for HTTP requests on TCP port 8091
------------- 2024-12-17 01:16:29 UTC ------------
warning: cannot start browser
Notice the the file sizes are grossly different.
So I went to next logical step: updated to version 2.23 to try it:
dougf@HPDesktop:~/fossil$ ./fossil version
This is fossil version 2.23 [47362306a7] 2023-11-01 18:56:47 UTC
dougf@HPDesktop:~/fossil$ ./fossil ui &
[12] 12688
Listening for HTTP requests on TCP port 8093
------------- 2024-12-17 01:44:24 UTC ------------
warning: cannot start browser
This is beyond me, Richard. I gave it my best show. It looks like it has to do with configuration.
(26) By Richard Hipp (drh) on 2024-12-17 11:14:31 in reply to 24 [link] [source]
The only supported build platform for Windows is MSVC. If you can get it to work with Cygwin or MingW32, then that's great. And if you have suggestions for minor changes that will help out Cygwin or MingW32, then they will be considered and likely implemented. But I'm not personally going to support non-MSVC builds.
The community edition of MSVC is free-ware. You can download and install it at no cost. I suggest you do that. Once you have MSVC installed on your Windows system, instructions for compiling can be found at https://fossil-scm.org/home/wiki?name=Release+Build+How-To. (You will also need Perl in order to compile OpenSSL.)
(27) By Doug (doug9forester) on 2024-12-17 18:08:46 in reply to 26 [link] [source]
I successfully built fossil on Windows 11 using MSVC which I already had installed. Thanks for that hint.
Problem when running "fossil ui --from ../trunk": The first browser page shows
This site can't be reached
localhost refused to connect
...
ERR_CONNECTION_REFUSED
If I wait a few seconds, the ui diff sometimes comes up, sometimes not. However, once I get to the ui, if I pick a couple of nodes on the timeline, I get the same error page and it doesn't resolve to the diff. The same behavior is exhibited for Cyg terminal and Windows terminal. If I run the command from "cmd", the error page shows and never gets to the ui.
(28) By Richard Hipp (drh) on 2024-12-17 18:15:09 in reply to 27 [link] [source]
That suggests that anti-malware settings on your Windows machine are not letting the connection through.
(29) By Doug (doug9forester) on 2024-12-17 18:46:47 in reply to 28 [link] [source]
fossil ui works fine. It's adding the --from that the failure occurs.
(30) By Richard Hipp (drh) on 2024-12-17 18:51:52 in reply to 29 [link] [source]
If you add the --systemtrace option to the "fossil ui ... --from" command-line, what do you see then? Are you using the latest source code - the stuff I checked in earlier today?
(31) By Doug (doug9forester) on 2024-12-17 21:21:20 in reply to 30 [link] [source]
From Cyg bash:
dougf@HPDesktop:~/.../iqutest/inc$ f ui --systemtrace --from ../trunk
Temporary files: C:\cygwin64\tmp\fossil\fossil_server_P8082*
Listening for HTTP requests on TCP port 8082
Launch webbrowser: start "" "http://localhost:8082/ckout?exbase=2e2e2f7472756e6b" &
SYSTEM: "start "" "http://localhost:8082/ckout?exbase=2e2e2f7472756e6b" &"
Type Ctrl-C to stop the HTTP server
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\cygwin64\tmp\fossil\fossil_server_P8082_000001_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\cygwin64\tmp\fossil\fossil_server_P8082_000002_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\cygwin64\tmp\fossil\fossil_server_P8082_000003_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\cygwin64\tmp\fossil\fossil_server_P8082_000004_cmd.txt" --nossl --localauth --repolist"
From cmd.exe:
C:\Users\dougf\Documents\AutoHotkey_fossil\iqutest\inc>fossil ui --systemtrace --from ../trunk
Temporary files: C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8083*
Listening for HTTP requests on TCP port 8083
Launch webbrowser: start "" "http://localhost:8083/ckout?exbase=2e2e2f7472756e6b" &
SYSTEM: "start "" "http://localhost:8083/ckout?exbase=2e2e2f7472756e6b" &"
Type Ctrl-C to stop the HTTP server
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8083_000001_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8083_000002_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8083_000003_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8083_000004_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8083_000005_cmd.txt" --nossl --localauth --repolist"
From powershell:
PS C:\Users\dougf\Documents\AutoHotkey_fossil\iqutest\inc> fossil ui --systemtrace --from ../trunk
Temporary files: C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8081*
Listening for HTTP requests on TCP port 8081
Launch webbrowser: start "" "http://localhost:8081/ckout?exbase=2e2e2f7472756e6b" &
SYSTEM: "start "" "http://localhost:8081/ckout?exbase=2e2e2f7472756e6b" &"
Type Ctrl-C to stop the HTTP server
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8081_000001_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8081_000002_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8081_000003_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8081_000004_cmd.txt" --nossl --localauth --repolist"
SYSTEM: ""C:\DougsTools\fossil.exe" http -args "C:\Users\dougf\AppData\Local\Temp\fossil\fossil_server_P8081_000005_cmd.txt" --nossl --localauth --repolist"
...
(32) By Florian Balmer (florian.balmer) on 2024-12-18 05:48:58 in reply to 31 [link] [source]
I think I've hit the same issue: the /ckout page sometimes "doesn't load" if the
'exbase' query parameter is set (via fossil ui --from ../OTHER/BASE/DIR
).
The debugger thinks it's a "use after free", and maybe this fits with the observation that the page "sometimes works".
Even though the stack trace indicates the source code locations, due to my lack of time (and skills, but with enough time I'm sometimes able to partially compensate for my lack of skills), I can't solve the problem, right now.
Exception and stack trace (Windows 11, Fossil [2dda151c40]
32-bit/i386 build):
3:011> g
HEAP[fossil.exe]: HEAP: Free Heap block 0211DE30 modified at 0211DE58 after it was freed
(2338.840): Break instruction exception - code 80000003 (first chance)
eax=013c9000 ebx=0211de30 ecx=00000200 edx=0000fffd esi=00000098 edi=01670000
eip=77e01a3e esp=014fede0 ebp=014fef48 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ntdll!RtlpAllocateHeap+0xc9e:
77e01a3e cc int 3
2:007> k
# ChildEBP RetAddr
00 014fef48 77e4211b ntdll!RtlpAllocateHeap+0xc9e
01 014fef8c 77def299 ntdll!RtlpAllocateNTHeapInternal+0x15b
02 014fefc0 77ea216c ntdll!RtlAllocateHeap+0xa9
03 014ff02c 77e00e99 ntdll!RtlDebugAllocateHeap+0xe2
04 014ff1a0 77e4211b ntdll!RtlpAllocateHeap+0xf9
05 014ff1e4 77def299 ntdll!RtlpAllocateNTHeapInternal+0x15b
*** WARNING: Unable to verify checksum for fossil.exe
06 014ff218 00deccbd ntdll!RtlAllocateHeap+0xa9
07 014ff278 00decec6 fossil!heap_alloc_dbg_internal+0x19d [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 359]
08 014ff29c 00dec4da fossil!heap_alloc_dbg+0x36 [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 450]
09 014ff2b4 00decf64 fossil!_malloc_dbg+0x1a [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 495]
0a 014ff300 00dec6eb fossil!realloc_dbg_nolock+0x44 [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 542]
0b 014ff350 00dca0b8 fossil!_realloc_dbg+0x6b [minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp @ 758]
0c 014ff36c 00d137e0 fossil!realloc+0x18 [minkernel\crts\ucrt\src\appcrt\heap\realloc.cpp @ 37]
0d 014ff37c 008e6cb6 fossil!fossil_realloc+0x10 [C:\...\fossil\build\util_.c @ 98]
0e 014ff390 008e7309 fossil!blobReallocMalloc+0x86 [C:\...\fossil\build\blob_.c @ 221]
0f 014ff3b0 008e70d3 fossil!blob_append_full+0xd9 [C:\...\fossil\build\blob_.c @ 359]
10 014ff3cc 009bc52d fossil!blob_append+0x33 [C:\...\fossil\build\blob_.c @ 372]
11 014ff798 008e518b fossil!vxprintf+0x22ad [C:\...\fossil\build\printf_.c @ 889]
12 014ff7b0 009230ff fossil!blob_appendf+0x1b [C:\...\fossil\build\blob_.c @ 1135]
13 014ff7c4 0092684e fossil!dfunifiedInsert+0x3f [C:\...\fossil\build\diff_.c @ 1429]
14 014ff834 0091faea fossil!formatDiff+0x48e [C:\...\fossil\build\diff_.c @ 2430]
15 014ff93c 0096b3c3 fossil!text_diff+0x8ca [C:\...\fossil\build\diff_.c @ 3208]
16 014ffa14 009697c7 fossil!ckout_external_base_diff+0x2d3 [C:\...\fossil\build\info_.c @ 793]
17 014ffa48 0097bfcb fossil!ckout_page+0x217 [C:\...\fossil\build\info_.c @ 871]
18 014ffaf8 00978926 fossil!process_one_web_page+0xbfb [C:\...\fossil\build\main_.c @ 2206]
19 014ffb60 0097a72d fossil!cmd_http+0x586 [C:\...\fossil\build\main_.c @ 2981]
1a 014ffbc4 0097b350 fossil!fossil_main+0x85d [C:\...\fossil\build\main_.c @ 978]
1b 014ffbd4 00d410b3 fossil!wmain+0x10 [C:\...\fossil\build\main_.c @ 688]
1c 014ffbf4 00d40efa fossil!invoke_main+0x33 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90]
1d 014ffc50 00d40d8d fossil!__scrt_common_main_seh+0x15a [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
1e 014ffc58 00d41138 fossil!__scrt_common_main+0xd [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 331]
1f 014ffc60 76565d49 fossil!wmainCRTStartup+0x8 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_wmain.cpp @ 17]
20 014ffc70 77e1cebb KERNEL32!BaseThreadInitThunk+0x19
21 014ffcc8 77e1ce41 ntdll!__RtlUserThreadStart+0x2b
22 014ffcd8 00000000 ntdll!_RtlUserThreadStart+0x1b
(33) By Richard Hipp (drh) on 2024-12-18 10:52:34 in reply to 32 [link] [source]
Do you have a test case that will reproduce this problem? I'm not able to make it fail here.
(34) By Florian Balmer (florian.balmer) on 2024-12-18 18:36:10 in reply to 33 [link] [source]
Now I wonder if this also fixes the problem reported by Doug. Probably not.
(35) By Doug (doug9forester) on 2024-12-18 19:07:12 in reply to 34 [link] [source]
I applied your patch, Florian, and it fixed my problem! Thanks. Let's get that into trunk asap, please.
(36) By Richard Hipp (drh) on 2024-12-18 19:10:17 in reply to 35 [link] [source]
Florian committed directly to trunk (as he should have in this case). I have already updated the Fossil binary that is running this forum with Florian's patch.
(37) By Doug (doug9forester) on 2024-12-18 20:42:53 in reply to 36 [link] [source]
To try to find the problem, I cloned fossil from trunk (how I did it, I forget). Now I want to diff (and update) between my local repository and fossil's. How do I do that?
(38) By Florian Balmer (florian.balmer) on 2024-12-19 14:50:30 in reply to 37 [link] [source]
To try to find the problem, I cloned fossil from trunk (how I did it, I forget).
The only way to clone a repository is to use the fossil clone
command.
Now I want to diff (and update) between my local repository and fossil's. How do I do that?
Use the fossil pull
command. Note you can also pull from a local
repository.
(39) By Doug (doug9forester) on 2024-12-19 16:15:12 in reply to 38 [link] [source]
I used 'fossil pull https://fossil-scm.org/home' to get the latest from fossil. But src/printf.c is not updated with your change. Is there more I need to do?
(40) By Stephan Beal (stephan) on 2024-12-19 16:19:42 in reply to 39 [link] [source]
fossil pull https://fossil-scm.org/home
You've over-doing that. After cloning, you no longer need to supply the URL when pulling or pushing (unless you're using multiple URLs with a single repo, which is a very rare use case).
But src/printf.c is not updated with your change. Is there more I need to do?
"pull" only updates your local repository but not your checkout. To do both at once use "fossil update trunk" instead, which will (if autosync is on, which it is by default) first pull, then merge any changes from your local copy into whatever was just pulled.
(41) By Andy Bradford (andybradford) on 2024-12-19 16:33:36 in reply to 39 [link] [source]
> I used 'fossil pull https://fossil-scm.org/home' This isn't strictly necessary. When you cloned the Fossil repository, it will have recorded the location from which you cloned. You can see what the current remote is by typing "fossil remote" in your working checkout. > Is there more I need to do? The "fossil pull" command only retrieves changes from a remote repository and writes them into your Fossil database, it does not update your working checkout. To do that you need to use either "fossil update" or "fossil checkout". These are some good references that you may find useful: https://www.fossil-scm.org/home/doc/trunk/www/quickstart.wiki https://www.fossil-scm.org/home/doc/trunk/www/ckout-workflows.md https://www.fossil-scm.org/home/doc/trunk/www/co-vs-up.md Basically synchronization between your repository and a remote repository is separate from the action of updating the working checkout. You can push, pull, or sync, and none of those operations will affect your working checkout. They only serve to keep artifacts in both locations. I thought that there was a document that detailed a typical scenario (e.g. clone, pull, update), and I thought perhaps the Quick Start Guide discussed that, but it seems it does not. It mentions using "fossil update" to fetch specific versions, but doesn't seem to mention "keeping your working checkout up to date". Andy
(42) By Andy Bradford (andybradford) on 2024-12-19 16:42:24 in reply to 37 [link] [source]
> Now I want to diff (and update) between my local repository By the way, after you have run "fossil pull", you can see the recent changes by just running "fossil ui -p timeline". You might do this, for example, if you want to see what has happened prior to running "fossil update". Andy
(25) By Florian Balmer (florian.balmer) on 2024-12-17 07:37:00 in reply to 1 [source]
I have two minor issues with the new /ckout page.
- On Windows,
fossil_assert_safe_command_string()
seems to reject backslashes in path name arguments to the--from
option for theui
command . Since many Windows shells insert backslashes on auto-completion, allowing them seems handy. Is this quick hack good enough:
Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -3297,11 +3297,19 @@
}
zInitPage = find_option("page", "p", 1);
if( zInitPage && zInitPage[0]=='/' ) zInitPage++;
zFossilCmd = find_option("fossilcmd", 0, 1);
if( zFrom && zInitPage==0 ){
+#ifndef _WIN32
zInitPage = mprintf("ckout?exbase=%T", zFrom);
+#else /* _WIN32 */
+ char *z = fossil_strdup(zFrom);
+ /* Use file_simplify_name() or file_canonical_name() instead of KISS? */
+ int i; for( i=0; z[i]!=0; i++ ) if( z[i]=='\\' ) z[i] = '/';
+ zInitPage = mprintf("ckout?exbase=%T", z);
+ fossil_free(z);
+#endif /* _WIN32 */
}
}
- When working with multiple check-outs and multiple temporary web UI windows,
I suddenly had a window with
/ckout?exbase=...
pointing to itself and showing a confusing empty diff. Should this case be intercepted, with a test similar to:
/*
** COMMAND: test-is-hardlink
**
** Usage: %fossil test-is-hardlink PATH1 PATH2
**
** Test if two file or directory names reference the same hard link.
*/
void cmd_is_hardlink()
{
verify_all_options();
if( g.argc!=4 ){
fossil_fatal("Usage: %s test-is-hardlink PATH1 PATH2",g.argv[0]);
}
fossil_print("%d\n",is_hardlink(g.argv[2],g.argv[3]));
}
int is_hardlink(
const char *zFn1,
const char *zFn2
){
#ifndef _WIN32
struct fossilStat s1, s2;
memset(&s1,0,sizeof(struct fossilStat));
memset(&s2,0,sizeof(struct fossilStat));
if( fossil_stat(zFn1,&s1,0)!=0 ) return 0;
if( fossil_stat(zFn2,&s2,0)!=0 ) return 0;
return s1.st_dev==s2.st_dev && s1.st_ino==s2.st_ino;
#else /* _WIN32 */
int rc = 0;
char *zId1=0, *zId2=0;
zId1 = win32_file_id(zFn1);
zId2 = win32_file_id(zFn2);
if( zId1!=0 && zId2!=0 ){
rc = fossil_strcmp(zId1,zId2)==0;
}
fossil_free(zId1);
fossil_free(zId2);
return rc;
#endif /* _WIN32 */
}