The one thing keeping me from switching fulltime is the friction of keeping unstaged changes in the repo. It's pretty common for me to have some throwaway lines like DEBUG = true or setLogLevel(LogLevel.VERBOSE) that are "permanent" in my dev environment but I never want to commit.
With git I can just `git add --patch` and skip over these at commit time (which I like, since I review my own code as I'm staging it), but jj doesn't have the index and pushes you to commit all changes by default. I know there are workarounds like `jj split` but it ended up being more work than git, where I can just not add those changes in the first place.
The ”staging” concept in git is something that I know really bugs a lot of people, especially beginners with git. Like ”I just want to commit, why is there this extra step?”, but I totally agree with you. Maybe it’s Stockholm Syndrome, but I really like that there’s an extra “look through your changes” procedure before committing, exactly for reasons like this.
It sounds like Stockholm to me ;) I don't think you _need_ the index to make partial commit work. I've used Mercurial first so I know "hg commit -i" exists.
Even if the staging concept is clear to someone, git cli terminology _is_ objectively very confusing and there are many articles written about it already (e.g., do I "add" to index? Is the index also referred as cached/Staged? Mixing different verbs and nouns everywhere). Are they all the same?)
I just wrote this to say it is not a necessary part of making a tool as powerful as git - Mercurial shows an example of a similar tool with a less confusing CLI.
Of course, git won so I just live with it. I enjoy teaching git new devs because once you explain the confusing terminology up front, they understand it faster.
A lot of the time, when I do my best to blow past that step, I forget to add new files to the commit. I wind up with all this needless CI activity on push, publish a whole PR for others to see, and generally waste everyone's time. Git's workflow really is based on this whole corpus of shared VCS experience, and it shows.
The downside to all that is that Git is _everyone's_ workflow, and nobody's at the same time. It's a compromise, and the tool does expose everyone to all the small little steps that are a part of that bigger experience. That said, if there was a more succinct workflow that was smart enough to flag simple mistakes for me, I would welcome it.
I second the comment made by the sibling poster that you should generally see the head commit in jj as your staging area, but treated like a real commit instead of the pseudo-commit that it is in git.
That said, I've ran into the same issues in Git with these sorts of perma-dev changes, and in every situation, I was happiest when I just moved that change into a config file or .env file that I could then gitignore. Even when I was careful, there were still accidents where I committed something I didn't mean to, or ended up losing my local configuration and needed to redo things. Whereas with an ignored config file, you can be certain that the changes in there will never get committed. Well, unless you switch to a version from before the config file was added to gitignore, but this is why adding this configuration as soon as possible is so useful!
‘jj split`isn't a workaround but their version of `git add -p`. The intent is to make the Index unspecial to make it easier to work with and not to get rid of it.
If there are usability gaps between the jj's active commit and git's index, then they should be reported.
- Make a commit off main that includes these private changes
- Make a commit for the work you’re doing
- Create a merge commit on top of these two changes and work there
This works because the “DEBUG=true” change is already committed, but in a commit you never push to the remote. jj makes it easy to continually squash the work you want to keep from the merge commit into one where it belongs. And, there is a “private commits” setting you can use to prevent accidentally pushing that commit somewhere.
I do that as well. Right now I keep a pre-commit script that prevents me from committing those by mistake but I would really like for git to have some kind of .gitignore for patterns in a line. Maybe a weekend project to tackle one day.
Out of interest, why not move those lines into a separate configuration file and put the whole thing in gitignore? With environment variables this is usually pretty trivial.
> I would have contributed patches to address these shortcomings if it were not for my third criticism, which addresses the elephant in the room: Jujutsu is a Google employee’s “20% project”, and thus all contributors are required to sign the Google CLA to participate. I refuse to sign any such thing and so should you. I have raised the issue on GitHub but it hasn’t attracted any sort of official response.
Unsure why he hasn't gotten a response but last I heard on this is they are focusing on defining their google-independent governance before which will give them room to address CLA's.
The biggest feature gap I noticed was the lack of hooks. Using Gerrit requires a commit hook to insert the change ID. jj's docs mention this specific use case, but their workaround (using a custom commit msg editor command that wraps vim) feels hacky.
Didn't bother looking further into it, not sure if this is a technical or ideological choice. Otherwise it reminded me about all the best parts of mercurial and git branchless. Pretty excited to get Fig-esque features in my external projects.
Yes, but the usefulness of "something new that replaces Git" would be severely limited by the fact that, well, everybody uses Git. And taking on Git is a task as daunting as, let's say, launching a new mobile OS and wanting to compete with iOS and Android. Jujutsu is gaining traction precisely because it can work on top of a Git repo, so people you are collaborating with don't even have to know that you are using it. Maybe Git experts don't need it, but I am an expert in programming who doesn't want to have to know every idiosyncrasy of the VCS tool I have to use in order to do my job...
With the advent of LSP I feel like we're almost to a point where you could version structures and not code. Like being able to follow how some class / method got cut in multiple pieces during a refactoring round.
Or maybe we need something more than plaintext to store code and the meta data around it before we can get to this point. I'm sure it has been already done multiple times in different ecosystems but there must be a way to standardize the information about code and use it in IDE and versioning tools.
Problem is metadata is taking much more time/space to fill in and context to be encoded will be awful lot of typing for a person.
When writing code context is encoded in the code and if you start on new project you need to read documentation and ask people around to pass you the context so you don’t need metadata. Or so to say all stuff that is in tickets and documentation plus what is in other teammates heads.
There’s just no way it will be efficient to somehow drop all of it while you want to do the code.
I decide to rename it and add a parameter: my IDE knows what I'm doing as it can change the new name everywhere the method is used. My versioning tool not so much: it can tell me some lines changed but it does not expose the fact "methodA has been renamed to superMethodB", that's something the user has to put in a commit file.
Add a moment when this method is refactored as 2 new methods and it starts being harder to follow in diff files. Most code forges already link commits to tickets: why not be able to directly link code constructs changes to tickets to telemetry artifacts? Mostly hidden through the IDE "task" management but all present in whatever ends in versioning. You could get git blame on steroids.
> Or maybe we need something more than plaintext to store code and the meta data around it before we can get to this point. I'm sure it has been already done multiple times in different ecosystems but there must be a way to standardize the information about code and use it in IDE and versioning tools.
This idea of storing more structured information (in the VCS or on disk) keeps coming up but I don't think it's necessary at all. The disk and the VCS can stay dumb. You can reconstruct the rich information after the fact.
It boils down to storing the right information and extracting it. Maybe you want to guard some checkpoints from bad/unstructured data. But that's just a check[1]. The serialization can be simple.
Well say you are blocked from storing bad data (according to the structure). Say you can also detect refactors like code moves (better than Git does, I guess just line moves). Again the storage can be dumb so that's fine. But you still need intentional commits; you won't get helped by a 500-line diff where all kinds of back and forth to solve three and half separate concerns are buried.
First of all you need good data in order to have something to extract. Which requires commit discipline.
[1]: And you don't get much from storing in a more rich format by itself. Just that you committed/stored syntactically correct/compilable artifacts. That's not nearly as rich as what you want. Because there are thousands of different intents (like you allude to) like refactorings -- all are valid in their own way so the structured representation can't have an opinion on it.
Are there new ideas possible? If so are they better? Those are open questions.
There are old ideas about versions that git is bad at though, what we need is something with the good parts of git while also adding those old ideas that are not in git.
I'm still bummed mercurial lost to git - mercural had its problems but git is so bad at branching people have just concluding branching is a bad idea which is just wrong if you ever used mercurial branches. Those who have used other version control systems likely have their own list of features they miss.
I'm happy enough with git most of the time. But the porcelain still sucks for a few things that feel like the should be basic and it doesn't feel like it's getting better or that any new tools have been written that fix the gaps for me.
One problem I've had recently is that I've wanted to store a large JSON file on GitHub (that's, importantly, modified slightly each commit), but with indentation it's over 100mb so GitHub doesn't allow it. I can strip out the indentation and that takes it down to 60mb or so, but the large objects are still in git history so they get rejected, so evidently I need to rewrite the git history.
Unfortunately, if you just take an old commit, strip the indentation from the JSON and try to rebase all the other commits on top of that, it'll fail as git treats each commit as a patch and the patches to the unindented JSON don't make sense. What I really want is to for git to treat each commit as a repository state, so that removing indentation from the state at commit A means that the patch for commit B adds all the indentation, and then I can just write a loop that rewrites each commit state. This seems like something that there should be better tooling for, I mean `git filter-branch` exists but I don't think it works for this usecase.
Edit:
Here’s what chatgpt suggests (for rust code):
```python
import os
import subprocess
def reformat_file(repo, commit, file_name):
# Check if the file exists in this commit
if os.path.isfile(file_name):
# Run cargo fmt to format the file
subprocess.run(["cargo", "fmt"], check=True)
# Stage the changes
subprocess.run(["git", "add", file_name], check=True)
def main(repo):
file_to_fix = "path/to/your/file.rs"
repo.filter_commit(reformat_file, file_to_fix)
```
And running with `git filter-repo --path path/to/your/file.rs --replace-callback reformat.py`. Ridiculous complicated.
>What I really want is to for git to treat each commit as a repository state, so that removing indentation from the state at commit A means that the patch for commit B adds all the indentation
`git rebase -X theirs` seems like it should be close, but commit B will only override conflicting chunks (so a change from A which doesn't conflict with B will persist, this shouldn't be a problem for your use case)
I use the "stackless" stacked PR git workflow mentioned in the article. I also add a bit of niceness to it so I don't have to remember the commit IDs:
So git has a notes feature, this is a simple note attached to a commit. It's intended for adding extra context to commit messages without changing the commit hash. Then there is a gitconfig for having these notes _follow_ the commit through rewrites such as rebases, squashes, amends, etc,.
All this together means that you write the branch name that you want in the note, use the git notes commands to two-way map this to the commit. Wrap this all in a git alias and it's golden.
Why is there no git-light VCS, with only the top 5-8 commands available? Push, fetch, commit, merge, rebase, branch, init... maybe I forget 1 or 2. I have to think extremely hard what command I used intentionally in the past 10 years (sometimes I used some arcane commands, only to fix some problems that was caused by some other arcane commands)
I've used git effectively and painlessly for many years, and pretty much all commands I ever use are commit, pull, push, checkout, merge and rebase. :) And diff if for whatever reason my IDE is not open already.
I think you're going about it in the wrong direction. Instead of learning what each command does, try learning what operations are possible (eg: move the current branch-ref to another commit, transplant a bunch of commits from one commit to another, etc). You just associate the commands to those operations through repeated use - no forced learning necessary. Recollecting the command is just a manpage away even for rarely performed operations. That makes it easy to learn not just the subcommands, but complex flag combinations as well.
This method also lends well to problem solving. You don't look at a repo and immediately think 'what commands will I use?'. You start with the problem. Then you formulate a solution as a sequence of operations that you know. You may be able to solve a problem with more operations even if you know fewer operations. Finally, convert each operation into a command and execute them.
Almost... but not what I'm looking for. I'm looking for something without actual git. I can also just ignore most of the ugly commands of git, but I'm thinking of something that doesn't make me think of what commands are worth remembering. I'm looking for "simple code versioning for dummies, that you can't break even if you tried hard"
Like the sibling comment mentioned, what you're looking for is fossil [0].
Fossil was created by Richard Hipp, who's also the creator of SQLite.
Fossil as a version management system gets completely out of the way.
In all the years over used Fossil, I've rarely had to use more than a few commands and have never had to understand any underlying concepts, let alone trying to figure out how to use the commands.
Additionally, fossil also comes with a wiki and a bug tracker, which is a bonus.
Not exactly what you asked for but if you are an emacs user, magit will make using git so much more pleasant. https://magit.vc/
Generally most IDEs will help you out with basic git tasks without even needing to know commands. There also dedicated GUIs for git.
Though for full time devs just learning how to use plain git isn't that hard. I very rarely have to look up git commands these days. You can limit yourself to the basic commands first.
Magit is more like a keyboard shortcut for those who already know their way around the git CLI. The direct mapping of CLI to short key sequences and the coherent visual feedback are the qualities that make magit so popular. I don't think someone who finds the CLI unpleasant will find magit to be any better.
With git I can just `git add --patch` and skip over these at commit time (which I like, since I review my own code as I'm staging it), but jj doesn't have the index and pushes you to commit all changes by default. I know there are workarounds like `jj split` but it ended up being more work than git, where I can just not add those changes in the first place.