feels the same when people say, "jq is hard i use python instead" like ok
feels the same when people say, "jq is hard i use python instead" like ok
Two examples from recent memory:
Someone merged the develop branch into their branch, then changed their mind and reverted the merge commit specifically (i.e. reversing all the incoming changes), then somehow merged all of this into the develop branch, undoing weeks of work without noticing. I had to go in and revert the revert to undo the mistake. Yes they messed up, but these things happen with enough people and time.
Another very interesting issue that happened to a less technical person on the team was that their git UI somehow opened the terminal in the wrong folder. They then tried to run some command which made git suggest to run 'git init', creating another git repo in that wrong location. Fast forward some days and we had an issue where people had to clean their repos, so I was in a call with the person helping them run the clean command. The UI opened the wrong location again, I helped them put in the command and it started cleaning. The problem was that this git repo was essentially at the top level on their disk, and since was a fresh repo every single file was considered a new file so it tried to delete EVERYTHING on their disk. This was of course mostly my fault for not running git status before the clean command, but this potential scenario was definitely not on my mind.
An example of something that the reflog isn't going to capture is a git reset --hard losing your unstaged changes, whereas the equivalent flow and commands in jj would allow you to get those contents back.
Git does version everything that is in the repository and all these states occur in the reflog.
Yes. I think that this difference is what introduces a lot of friction, both in the model, and how people use it. The divergence between the files that exist on disk inside your working copy and what's actually tracked means lots of opportunities for friction that go away once you decide that it should. That doesn't mean things are perfect, for example, by default jj only snapshots the filesystem when you run a `jj` command, so you can still lose changes from in between those, you need to enable Watchman to get truly full logging here.
> all these states occur in the reflog.
Well, let's go back to the documentation for reflog:
> Reference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository.
It only tracks changes to refs. That is, the states that refs have been in. So, one big example is detatched HEADs: any changes you make to those, which still are contents of the repository, are not tracked in the reflog.
Even for refs, there's differences: the reflog says "ref was in state x and changed to state y" without any more details. jj's oplog keeps track of not only the state change, but the reason why: "rebased commit <sha> with these args: jj rebase -r <sha> -d trunk"
The reflog only tracks individual refs. Say we rebase multiple commits. The reflog still just says "the head of this branch was in state x and changed to state y" but the oplog says "a rebase happened, it affected all of these commits refs in these ways," that is, it's just inherently more rich in what it tracks, and does it across all relative commits, not only the refs.
This doesn't mean the reflog is bad! It's just a very specific thing. Git could have an operation log too, it's just a different feature.
$ git checkout HEAD
$ git commit --allow-empty -m "_"
$ git checkout master
$ git reflog
a91 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: checkout: moving from b94 to master
b94 HEAD@{1}: commit: _
28d (origin/feature, feature) HEAD@{2}: checkout: moving from feature to @
> Even for refs, there's differences: the reflog says "ref was in state x and changed to state y" without any more details. jj's oplog keeps track of not only the state change, but the reason why: "rebased commit <sha> with these args: jj rebase -r <sha> -d trunk"> The reflog only tracks individual refs. Say we rebase multiple commits. The reflog still just says "the head of this branch was in state x and changed to state y" but the oplog says "a rebase happened, it affected all of these commits refs in these ways," that is, it's just inherently more rich in what it tracks, and does it across all relative commits, not only the refs.
68e HEAD@{15}: rebase (finish): returning to refs/heads/feature
68e HEAD@{16}: rebase (pick): message #6
7ff HEAD@{17}: rebase (pick): message #5
797 HEAD@{18}: rebase (pick): message #4
776 HEAD@{19}: rebase (pick): message #3
c7d HEAD@{20}: rebase (pick): message #2
f10 HEAD@{21}: rebase (pick): message #1
c0d HEAD@{22}: rebase (start): checkout @~6
a7c HEAD@{100}: rebase (reword): message ...
3b1 HEAD@{229}: rebase (reset): '3b1' message ...
4a4 HEAD@{270}: rebase (continue): message ...jj still ends up keeping information in here that the reflog doesnt, but you're right that these aren't the strongest points.
I think Git will just gain a oplog. You just need to append a commit hash to a list before each command and implement undo as remove item and checkout. The hardest thing will be race conditions, but Git already knows how to be a database.
--update-refs, --no-update-refs
Automatically force-update any branches that point to commits that
are being rebased. Any branches that are checked out in a worktree
are not updated in this way.
If the configuration variable rebase.updateRefs is set, then this
option can be used to override and disable this setting.Yes, this is something, that JJ provides and Git does not.
Git has lots of sharp edges that can get hairy or at least tedious really rapidly. You have to keep a ton of random arcana in working memory at all times. And a bunch of really useful, lovely workflows are so much of a pain in the ass that you don’t even conceive of doing them.
I learned jj in one day and never went back.
I'm not a welder or a metalworker, but I do know how to weld. I use a welder a handful of times per year when I need/want to. Welding is dangerous, and achieving excellence is a difficult and long road. But I can use the same tools as a pro and still get a few pieces of metal stuck together without having to relearn and restudy the whole system each time something goes wrong.
I haven't used jj in anger yet, but I think it might at least be approaching that style of developer tool.
Now, once you teach them it’s a commit graph with names, some of them floating, some people get it.
The thing is, not everyone is comfortable with a commit graph, and most people are not - just like people get lists and arrays but graphs are different.
So I agree with you on principle ( it shouldn’t be difficult), but most people don’t have a graph as a mental model of anything, and I think that’s the biggest obstacle.
You can see where you were and hard reset back, no matter what state you are in.
The feeling of complexity comes from not yet understanding that commits are just sets of changes to files. They are then thrown off the scent by new terms like origin clone vs push and pull, merge vs rebase, HEAD increment notation vs other commit hashes.
Once people start with a local understanding of using git diff and git add -p they usually get the epiphany. Then git rebase -i and git reflog take them the rest of the way. Then add the distributed push and fetch/pull concepts.
I understand how to do these things, but git’s interaction model makes it tedious at best and hard at worst.
jj’s interaction model makes these things simple, straightforward, and obvious in the overwhelming majority of cases.
I don't see this anywhere nearly as drastically with other tools.
It’s exactly like folks in 1995 telling you to rtfm when you’re trying to install Linux from a floppy disk. It’s doable, but annoying, and it’s not that easy.
Just in case, I'm talking about the Pro Git book [0]. I remember reading it on my kindle while commuting to office by train. It was so easy to understand, I didn't even need a computer to try things. And it covers everything from bare basics, to advanced topics that get you covered (or at least give you a good head start) if you decide to develop your own jujutsu or kurutu or whutuvur.
The book says that ‘ To really understand the way Git does branching, we need to take a step back and examine how Git stores its data’ then it starts talking about trees and blobs.
At that point you’ve lost almost everyone. If you have a strong interest in vcs implementation then fine, otherwise it’s typically the kind of details you don’t want to hear about. Most people won’t read an entire book just to use a vcs, when what they actually want to hear is ‘this is a commit graph with pointers’.
I agree with you : the information is there. However I don’t think you can in good faith tell most people to rtfm this, and that was my point.
I can, and I do.
The explanation in that book creates a strong coherent and simple mental model of git branching. I honestly can't think of a better explanation. Shorter? Maybe. But "graph with pointers" wouldn't explain it.
So let's agree to disagree.
The git mental model is more complex than cvs, but strangely enough the docs almost invariably refer to the internal implementation details which shouldn’t be needed to work with it.
I remember when git appeared - the internet was full of guides called ‘git finally explained ‘ , and they all started by explaining the plumbing and the implementation. I think this has stuck, and does not make things easy to understand.
Please note I say all this having been using git for close to 20 years, being familiar with the git codebase, and understanding it very well.
I just think the documentation and ui work very hard towards making it difficult to understand .
Hell, I've personally mentored people who struggled with git and I could feel their struggle.
I'm not saying that learning git was an insurmountable task for them, but their struggle was not something that I had to go through.
But whatever state I'm in, I'm sure I can reset back to where I were using reflog.
It does `git pull <default remote> foo`.
> vs a remote
It gives an error, because you haven't specified the remote.
I don't know what behaviour you find intuitive here?
> how do you fix it if you messed up/which is preferred when both exist?
git pull is YOLO mode, so I never do it, but I would just reset the branches where I want them to be? You get a summary with the old and new commit hashes, so resetting is really easy.
And the significant time and effort amounts to a total of 15 seconds.