A newcomer's perspective

Hello there!

EDIT: I now realized what I’m trying to achieve and why isn’t clear at all, please see my response below

As stated in the introduction thread, I really like how pijul works, and would like to contribute to the project. I played around and found a few things I would like to work on. As I don’t know if these changes make sense at all, I thought I’d better ask first!

You can think of this list as a combined feedback/discussion/wish list.

Implement pijul status

I don’t know about you, but I spend a lot of time switching tasks, and forgetting about things. Here are some examples of things I forget:

  • what unstaged changes do I have
  • what have I staged
  • what branch / channel am I even working on
  • have I pushed my changes
  • what time is it again?

(git status is my second most used command, behind ls)

Implement pijul merge

It is very much critical, for at least these use cases:

  • merging channels with a lot of changes in different areas, where hand-picking from the log is error-prone
  • automating merge branch
  • long running branches that need to be “rebased”. sometimes, a feature needs to be worked on for quite some time, and receives changes back from its base channel in order to still be relevant. These rebases sometimes involve hundreds of changes from the base channel.

It seems to me that what’s need is to run a diff on channel’s set of changes. I don’t think there currently are cached data structures available to do this? Here’s my take: prolly trees are a very good tool for the job. They are a probabilistic sorted shared data structure (like merkle trees) set where order of insertion / deletion does not matter. It was, I believe, first introduced in noms, a versioned database.

Make the output of various commands friendlier
  • color the output of pijul diff
  • color the output of pijul log
  • show change authors and line ranges in pijul credit
Naming tweaks
  • the naming of pijul change is very odd: it implies the command changes something, yet it shows a change. I legitimately had a very hard time finding it.
  • pijul is a bit long for a VCS binary name (It also felt slightly awkward to type at first, but that’s a locale dependant thing). I’d love to have pj to be available by default.
Better documentation
  • Even though the theoretical background of patches themselves is well documented, I didn’t find documentation about the software architecture of the project. That’s an issue, as new developers need to be able to navigate the code. A diagram of data and processes would be amazing too.
  • Some subcommands have no available documentation, such as ls or debug

I’ll definitely try to tackle some of these by myself!

What do you think?
Did I miss something?
Anyone wants to help me implement / implement one of these?


Victor

Hi! Thanks for the comments, but there’s been a bit of work done on Pijul already, these commands are indeed useful, which is why some of them have already been implemented:

  • pijul status is called pijul diff (you can add -sU if you want).
  • pijul merge, well… the whole point of Pijul is to merge patches, so we’d be in trouble if we hadn’t implemented that. Try to look at pijul apply or pijul pull.
  • you can make aliases in your favourite shell, for example in .zshrc: alias pj=pijul.
  • some command names have been debated here on the discourse and the resulting names are the fruit of a consensus, pijul change is one of them.

Other than that, we do welcome help, and your idea of helping write documentation is great!

Hello!

I think there’s a misunderstanding about my intentions. I believe pijul does versioning better than git, and I’d very much like to daily drive it. I’m hopeful that eventually, pijul will get the recognition it deserves: it’s an impressively well built piece of software, both in terms theory and practice.

I also think the user experience of pijul isn’t as good as its versioning abilities. In fact, I was surprised by how disoriented I found myself during the first few hours. In the end, I found ways to do all I wanted, but these didn’t feel as straightforward as I wish they had been. And that’s fine, really! Pijul is an opensource tool, and I don’t feel entitled to anything.

I would like to contribute bringing pijul to a point where pijul is easily recognized by newcomers as an improvement over git. I think the core improvement is already there, and what’s missing it workflow improvements.

And that was the point of my first message: what were the things that, as a newcomer, found myself looking for: documentation, commands that exist but couldn’t find, or commands that don’t exist.

Reading my message back now, it’s a terrible message, as none of what I wrote above is obvious: I just wanted to share what crossed my mind, which is not good enough. I should have known better, and I’m sorry.

That said, I think there are some misunderstandings:

  • there are a number of useful things pijul status could show that pijul diff -su does not:

    • the current channel (I know I can get it with pijul channel)
    • are there unpushed changes (I don’t know how to get that)
    • are there unpulled changes (I don’t know either)

    even if there are ways to show there separately, I’d love to have the option to show them all at once.

  • I’m not referring to merging changes, but merging channels. I’ve inferred it’s not currently straightforward from this note


Victor

1 Like

I’ve said on Zulip:

I’m with you, thinking there should be a status command.
This has been discussed
Is there an equivalent of `git status`?
Request for comments: Listing files with conflicts in `pijul status`
Git status equivalent

As for merge, I think pull and push do more than the newcomer is led to believe.
Channels appear to be a late addition, just so that Git folks will be comfortable, but the channel doesn’t make much sense to me. I tried to use a channel to test someone’s changes, but Pijul gave a merge conflict when switching channels! See identity management on Zulip.
The thing that I struggle with is the dependencies. You can try to make a channel that contains a single change, but it will only succeed if that change creates a file. If it changes something in an existing file, it is dependent on other changes, so those get pulled in also.

No worries, I totally understood what you meant, and appreciate the positive energy! I don’t consider a disagreement a bad thing, but rather as a starting point of an interesting discussion.

One point where we may disagree is whether Pijul should look like Git as much as possible to a beginner, or if we could just allow people to learn a different way of working, whether or not they already know Git.

About merging channels, Pijul doesn’t have that notion, Pijul only knows about applying patches, and absolutely never merges versions. One issue is that many users expect commands named like in Git/SVN to do the same thing as in these tools, which is almost never the case in Pijul. That would be, in my opinion, a recipe for a UX disaster.

One command that does something comparable to “merging channels” (but again, this doesn’t “merge” anything) is pijul pull: compare two channels, and apply the patches resulting from the comparison.

One thing that is needed is better explanation of merge conflicts - how to read the way it is or changed to be more intuitive.
Also needed is the ability to show context in diff or change.
And – a good way to cancel out of an interactive command.

They’re not: I wrote an entire database engine (Sanakirja), whose sole purpose is to make that fork operation possible. Sanakirja is the “inner core” of Pijul; it’s a very small engine (making it really fast), but it took more time in testing and debugging than the rest of Pijul.

Sorry for how that came across, but it is how it looks from the outside…

Edit: you also made a comment to that effect at one point

One point where we may disagree is whether Pijul should look like Git as much as possible to a beginner, or if we could just allow people to learn a different way of working, whether or not they already know Git.

We’re on the same page then! The goal should be a smooth and intuitive user experience, not making a git lookalike.

One command that does something comparable to “merging channels” (but again, this doesn’t “merge” anything) is pijul pull: compare two channels, and apply the patches resulting from the comparison.

Just to ensure we’re on the same page, by “merge” (which should really be called pull, you’re right) channel A into channel B, I mean: compute the set of patches which are in A but aren’t in B, and apply these onto B.

And indeed, as changes commute, it makes total sense for pull / push / merge to all be somewhat the same thing (unless it’s not?). Unfortunately, the documentation of both pull and push says they only work between a local and a remote channel, which prevents quite a bunch of common use cases (such a “rebasing” onto a local channel and fixing conflicts before submitting it to the main branch).

Where is that? It needs changing.

https://pijul.org/manual/reference/push.html
https://pijul.org/manual/reference/pull.html

EDIT: unless “remote” means “target branch” not pijul remote remotes?

I wanted to say that the manual is out of date (it is), but in this case, it matches the help text for the commands.
The word remote shouldn’t be used there since that implies some other computer.
I think I had this same problem with the docs, because I couldn’t figure out how to do some things until someone showed examples of push and pull between local copies of repos.

I agree that Pijul probably shouldn’t mimic git (and hence possibly inherit it’s UX errors), but on the other hand it seems that majority of new Pijul users will be git users, so this kind of expectations and feedback should be expected. A lot. Maybe these differences and decisions need to be communicated very clearly.

I recall that there already was a page “Pijul for Git users”, but perhaps it should be promoted very thoroughly otherwise there will be a ton of misunderstanding…

I’ve also had a number of in-person discussions where I insisted that Pijul worked differently. No matter what I said, my interlocutors couldn’t understand anything other than “it seems easier, so they must have just renamed the commands”.

Yeah… git is too hardwired into programmer’s minds, unfortunately. I guess you’ll have to balance between openness to get a constructive feedback and firm understanding of what you’re after in the Pijul design. That’s why I thought that maybe in future some document which explain why this and this is so and so, compared to git, can help.

Something that is not necessarily obvious in terms of how to think about using pijul is how to address complex workflows where one has many different incomplete efforts in flight simultaneously. In git, this is done using branches; in pijul is this intended to be managed using channels? Using separate copies of the repository?

I think the reason that you see multiple requests for a pijul status command is because in git, status is the command that helps users solve the “where was I?” problem when working on multiple independent efforts in parallel, and is then incidentally also convenient when the question is “what have I just done, and does it form a cohesive unit that I want to record?”

1 Like

On this topic, one thing I might add, which quite possibly has been discussed before.

I describe git as requiring me to have a masters’ degree in graph theory to understand it, and like being given a loaded handgun with no safety and being asked to point it at e.g. my company’s shared github repos to use it. It’s very unsafe by default and doesn’t come with many confirmation features for destructive actions.

Power-users may find this makes their job much quicker, but having used bazaar as an alternative interface to what are still git-style repositories, it is very much easier to use for me because of the way it took the approach of always being safe by default. If I ask it to do something that doesn’t make much sense or isn’t straightforward, it stops me or asks for a confirmation flag beforehand. I have to go back and modify my command in order to do something, rather than its assuming that it will do the thing anyway even if that’s not what I likely wanted. Reverting or removing a file always adds a backup suffix rather than really deleting it. I can’t push to a lossy destination without confirming this. Merging when the current directory contains uncommitted changes, pulling or pushing when branches have diverged, …, you presumably get the idea.

As pijul grows, I’d very much like to see a similar methodology taken to the command line. I agree that git’s choice that commands can mean two different things is bad, but I think when it comes to something as critical as tracking versions of important data, making things as risk-free and safe to use is one of the most important UX design features, we wanna reduce stress on users and thus allow integration with the software, rather than making version controlling a massive amount of mental load, which is what some other tools have succeeded in doing for me (and I’m a C++ programmer, so it’s not like I’m not technically-minded).

This for me is more important than the exact semantics of what individual commands are called or how they work. zfs has a really nicely-formatted CLI (all Solaris seems to be really, I think it comes from BSD), but I don;t use it except for from my wrapper scripts for most operations, because once I run sudo zfs destroy, that’s it, my filesystem is permanently gone (and maybe I only meant to destroy one snapshot, but, too late now if I forgot an at sign somewhere). I want something to show me what I am about to do and confirm beforehand, so I wrote my wrapper and always use it.

Haven’t managed to use pijul much recently, so I can’t remember any examples off-hand, but I do recall noting at some point that it felt a bit more like the silently-do-something-anyway rather than the prompt-if-I-really-want-to approach. Obviously it’s not quite as bad as destroying filesystems, but some of the things we can do with VCS are still potentially quite destructive, so I think it’s worth bearing in mind.

3 Likes

There was a time when I aliased git commit to ci and git checkout to co and once I have mistyped and executed co . and irreversibly lost a day of hard work. I still remember that feeling.

Of course I shouldn’t have make such a stupid alias (removed it immediately), but if git at least asked for confirmation, this might have stopped me.

1 Like

Hello, I know this thread has taken a few turns, but wanted to chime in on the request for a “pijul status”.

I wrote an early version (0.10 or 0.11 if memory serves), but it’s since been dropped - I think the argument is that other commands cover it (“pijul channel” for current channel, “pijul diff -su” to view unrecorded changes in tracked files + untracked un-ignored files).

As pijul has some basic support for subcommands I’ve gone and implemented my own pijul-status script and just placed in on my PATH:

#!/usr/bin/env bash
set -euo pipefail

# Give an overview of the current state, including:
#
# * Current channel
# * State of tracked files with changes
# * Untracked files

current_channel() {
	local c=$(pijul channel | grep '^\*')
	printf "On channel %s\n" "${c:2}"
}

pijul_status() {
	pijul diff --short --untracked | awk -f <(cat - <<-'EOD'
	        BEGIN {
			ci = 0
			ui = 0
	        }
		/^[MR] .*/ {
			changes[ci++] = "modified" substr($0, 3)
		}
		/^A .*/ {
			changes[ci++] = "added" substr($0, 3)
		}
		/^D .*/ {
			changes[ci++] = "deleted" substr($0, 3)
		}
		/^U .*/ {
			untracked[ui++] = substr($0, 3)
		}
		END {
			if (ci > 0) {
				printf("\nUnrecorded changes:\n")
				printf("  (use 'pijul record' to record a new patch)\n")
				printf("  (use 'pijul reset' to discard changes)\n")
				for (c in changes) {
					printf("    %s\n", changes[c])
				}
			}
			if (ui > 0) {
				printf("\nUntracked files:\n")
				for (u in untracked) {
					printf("    %s\n", untracked[u])
				}
			}
			if (ci == 0 && ui == 0) {
				printf("nothing to record, working copy clean\n")
			}
		}
	EOD
	)
}

current_channel
pijul_status

Here’s an example from when I was messing around with the pijul sources themselves (pl = pijul):

$ pl status
On channel main

Unrecorded changes:
  (use 'pijul record' to record a new patch)
  (use 'pijul reset' to discard changes)
    modified libpijul/src/change.rs
    modified libpijul/src/change/text_changes.rs
    modified libpijul/src/pristine/patch_id.rs
    modified libpijul/src/unrecord/mod.rs

Untracked files:
    pijul/Cargo.lock

I personally love Git’s status output, I use it aaaaall the time. If you like it, feel free to use it. Note that’s it’s not crazy fast.

The only thing it’s missing compared to the previous built-in implementation is that it cannot show files that are in conflict. I don’t know if there’s any subcommand that provides this information. There’s a nice warning printed when a conflict is introduced, but I haven’t found a way to list known conflicts.

Having a section called “Files with conflicts:” was the main motivator for creating the initial builtin “pijul status”, but I’m happy to have my own status command if I can scrape the conflict information from somewhere else.

5 Likes