[HN Gopher] Jujutsu - A Git-compatible DVCS that is both simple ...
       ___________________________________________________________________
        
       Jujutsu - A Git-compatible DVCS that is both simple and powerful
        
       Author : rolisz
       Score  : 524 points
       Date   : 2022-02-19 17:17 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | habitue wrote:
       | I like that this is not "a dvcs written in rust" but rather "a
       | dvcs with these awesome improvements over git." which
       | incidentally happens to be written in rust because of course it's
       | the right language for this.
        
         | ParetoOptimal wrote:
         | I was really hoping it was implemented in Rust as I read the
         | Readme on mobile and was happy to see a cargo.lock after
         | clicking 'view code'.
        
       | kazinator wrote:
       | In git you can reorder any sequence of commits without any
       | conflicts. Howwever, there is no nice "porcelain" for it.
       | 
       | The basis for it is the _read-tree_ command.
       | 
       | In git, every commit is a snapshot and not a delta. (Repeat that
       | three times.)
       | 
       | Any arbitrary snapshots of files can be arranged into a git
       | history. They don't even have to be related. We could take a
       | tarball of GCC, and make that the first commit. Then a tarball of
       | Clang and make that the second commit.
       | 
       | The _read-tree_ command will read any commit 's state into the
       | index, and from there you can make a commit out of it.
       | 
       | To reorder some N commits you're looking at, save all of their
       | hashes somewhere, and then rewind the branch: git reset --hard
       | HEAD~N. Then use git read-tree to read those hashes in whatever
       | order you want, committing them one by one. To reuse their commit
       | messages you have to use commit -C <hash>, though most them
       | likely don't make any sense, because the text of commit messages
       | usually talks about changes between a commit and its main parent.
       | 
       | What will happen is that your history now as N commits which
       | represent the same _states_ as the N you had there before, in a
       | different order. For instance if you reverse them, then the
       | oldest commit has all the features (is the same code baseline) as
       | what the newest HEAD was previously. And then the subsequent
       | child commits basically remove all the changes that were made, so
       | the latest now looks like what the N-th looked like.
       | 
       | How I sometimes use this:
       | 
       | Suppose I made a fairly complex change that I would like to break
       | up so that it is presented as a sequence of two or more states of
       | the code.
       | 
       | There are cases when the following workflow is easy: first I make
       | a commit out of the changes. One commit with everything. That
       | commit is what I want the final state to look like. Then I revert
       | some of the changes to produce the state before that state. If I
       | have mostly been adding things, this might consist of just
       | deleting them. Or I can do a git reset --patch HEAD^ to
       | selectively revert. I commit this penultimate state. Then repeat
       | the process: revert some more changes from that one, commit and
       | so on, as many times as I see fit.
       | 
       | So what I end up with is the states of the code I want to present
       | as a history, but exactly in the wrong order. Using "git rebase
       | -i" doesn't work nicely; there are ugly conflicts, and some of
       | them have to be encountered twice. Here is where the git read-
       | tree trick comes into play: I simply reverse those exact states
       | of the code to put them in the right order on the branch. After
       | that I might do a rebase -i just to reword the commit messages to
       | frame the code states from the POV of being changes from their
       | parents.
       | 
       | You might think: why not just "git commit --patch" from the
       | original working state to produce commits in order. The reason is
       | that doesn't always make sense. For that you had to remember to
       | make the commit as you were working. Because say you refactored
       | something and then made a change. You can't easily do a "git
       | commit --patch" which separates the refactoring from the change.
       | Sure, if you do the refactoring and then a commit, and then make
       | the change, you are good. But suppose you've conflated them
       | already; now what? You can commit everything and then back out
       | the changes that were done on top of the refactoring, and commit
       | that. Then reorder the two states.
        
         | glandium wrote:
         | What I would do in this case is two rebase -i. Say you start
         | from:                 A       B
         | 
         | And you want:                 state-of-B       state-of-A
         | 
         | I'd do a rebase -i with:                 pick A       x git
         | revert HEAD       pick A       pick B
         | 
         | Let's call the resulting commits of the above a, b, c and d.
         | With the following rebase -i, you get what you want:
         | pick a       squash d       pick b       squash a
         | 
         | In practice, I just do git revert HEAD; git cherry-pick HEAD~
         | before working on B, so I only really do one rebase.
        
           | kazinator wrote:
           | Problem is, you may get ugly conflicts along the way which
           | serve no purpose to the end goal, and have to be resolved
           | more than once in different directions.
           | 
           | It's an abstraction inversion to be doing that. The system
           | doesn't work with diffs and merges: that's just layering on
           | top. The system contains snapshots, and so if you want to
           | rearrange snapshots in a different order, that's the best
           | abstraction layer to work at.
        
             | glandium wrote:
             | Oh, I actually messed it up. Which in hindsight I don't
             | know why because it's really much simpler than what I
             | started with... but then I usually do it with more
             | intermediate steps, and on an actual command line, not on a
             | mobile phone...
             | 
             | Anyways:
             | 
             | You start with:                 original-state         A
             | final-state         B       intermediate-state
             | 
             | You want                 original-state         X
             | intermediate-state         Y       final-state
             | 
             | What you just need to do is:                 git revert
             | HEAD
             | 
             | Which gives you:                 original-state         A
             | final-state         B       intermediate-state
             | revert (C)       final-state
             | 
             | Then X = A + B and Y = C, so with one rebase -i:
             | pick A       squash B       reword C
             | 
             | No conflicts. The important thing is that with appropriate
             | reverts and reapplication of commits, you can make your
             | history contain the states you want in the order you want,
             | even if in between you have repeated states in the wrong
             | order. Then you squash things so that you only keep the
             | states you wanted in the first place.
             | 
             | Edit: but yes, you can achieve the same outcome with read-
             | tree or checkout.
             | 
             | Edit2: come to think or it, you can probably do what you
             | want with a couple git replace --graft and a noop filter-
             | branch.
        
         | cryptonector wrote:
         | TIL about `git read-tree`. Thanks! I think it will prove very
         | useful for me. That said, the easiest way to reorder commits is
         | to `git rebase -i $some_base` and then reorder the `pick` lines
         | in your $EDITOR into the order you want.
         | 
         | > In git, every commit is a snapshot and not a delta. (Repeat
         | that three times.)
         | 
         | Yes, but every commit also is notionally a delta. That the
         | delta is reconstructed as needed is not terribly important.
         | It's best to accept a commit as both, a reference to a state of
         | the world, and as a delta to the recorded parent(s).
         | 
         | Lastly, I avoid `git reset --hard`. I often have extant changes
         | that I don't want to lose. Instead what I do is `git rebase -i
         | --autostash`.
        
         | mastazi wrote:
         | > In git, every commit is a snapshot and not a delta.
         | 
         | I know this, but also I cannot reconcile this whit what happens
         | when you cherry-pick a commit from another branch. I'm confused
         | because cherry-pick really seems to be taking out the delta not
         | the snapshot.
         | 
         | I'm thinking that cherry-pick takes that commit and makes a
         | diff with its parent and then that's what you get when you call
         | it. Is it how it works behind the scenes?
         | 
         | I'm also thinking that the fact that each commit has at least
         | one parent means that, conceptually, we can use it as if it was
         | a delta (at least in the case of commit with one parent only),
         | if you get what I mean.
         | 
         | EDIT: I'm not familiar with the internals of Git, just a user.
         | Commenting out of curiosity.
        
           | kazinator wrote:
           | When you cherry-pick a commit from another branch, it's not
           | doing anything like a read-tree to make your current work
           | look like that commit's snapshot state. It's doing something
           | like three-way merge between that commit, your baseline and a
           | common ancestor (I'm guessing: the same one that would be
           | identified by git merge-base <hash0> <hash1>.) That's why
           | cherry-pick identifies conflicts.
           | 
           | A cherry-pick deos not just do a diff with its parent 0 and
           | then patch it onto your work. In many cases, that wouldn't
           | work because that's not a three-way-merge, but a two-way
           | merge, which has disadvantages.
           | 
           | However: there may be situations when the commits are so
           | distant, it might make sense just to turn that one into a
           | patch and work the patch onto your baseline. Even if that
           | needs manual work, it can be simpler. You will only get
           | conflicts (patch hunk rejects in that case) that are relevant
           | to that change. I've had lots of experience working with
           | patch stacks (both before and after Quilt was introduced to
           | make that a bit easier) so I'm comfortable migrating patches
           | from one code base to another without a three-way-diff
           | process within version control.
        
             | geofft wrote:
             | It's doing something weirder than that, but "it applies a
             | diff between a specified commit and its parent on top of
             | your current work" is more accurate/intuitive than "it does
             | a three-way merge with a common ancestor". No common
             | ancestor is involved.
             | 
             | The first hint that it's doing something interesting is
             | that the implementation of cherry-pick is in revert.c,
             | because it's implemented as a variant of revert: https://gi
             | thub.com/git/git/blob/v2.35.1/builtin/revert.c#L23...
             | 
             | Both the "revert" and "cherry-pick" operations initialize a
             | sequencer object with a single operation in the sequence.
             | (This is the same mechanism underlying "git rebase -i").
             | 
             | From there we can find the call to
             | sequencer_pick_revisions, which leads us to the sequencer
             | implementation, where there's a fast-path for ordinary
             | cherry-picks leading us to a short function single_pick,
             | which in turn calls do_pick_commit:
             | https://github.com/git/git/blob/v2.35.1/sequencer.c#L2066
             | 
             | This operation then does the following:
             | 
             | - Determine what we're applying a diff on top of: https://g
             | ithub.com/git/git/blob/v2.35.1/sequencer.c#L2083-L2...
             | 
             | - Find a parent commit. If the commit has more than one
             | parent, it requires you to specify a "-m" option indicating
             | which parent to diff against. https://github.com/git/git/bl
             | ob/v2.35.1/sequencer.c#L2109-L2...
             | 
             | - Set up the commit message and some other stuff.
             | 
             | - Set the variable "base" to the parent it found and "next"
             | to the commit being cherry-picked. https://github.com/git/g
             | it/blob/v2.35.1/sequencer.c#L2187-L2...
             | 
             | - Assuming no merge strategy (or either of the standard
             | strategies "ort" or "recursive") was specified on the
             | command line, call do_recursive_merge. https://github.com/g
             | it/git/blob/v2.35.1/sequencer.c#L2237-L2...
             | 
             | In turn, do_recursive_merge calculates a head_tree from the
             | current HEAD
             | (https://github.com/git/git/blob/v2.35.1/sequencer.c#L645),
             | and then calls either merge_incore_nonrecursive (the
             | current default, from the new "ort" merge strategy) or
             | merge_trees (from the older "recursive" merge strategy)
             | with three _trees_ (i.e., with no further ancestry
             | information): the base is the parent it found, and the two
             | sides being merged are your current HEAD and the (tree of)
             | the commit being cherry-picked.
             | 
             | That is to say, at no point does it care whether the two
             | commits even _have_ a common ancestor! It 's just doing an
             | operation on trees. It is doing a three-way merge, yes, but
             | the graph of the merge it's doing is one that potentially
             | doesn't actually exist in reality.
             | 
             | Or, in other words, it's trying to compute the tree that
             | could be equally well described as the result of
             | 
             | - applying the diff of the commit you're cherry-picking to
             | your current HEAD
             | 
             | - applying the diff between your current HEAD and the
             | parent of the commit you're cherry-picking to the commit
             | you're cherry-picking
             | 
             | So this is more powerful than purely applying a diff with
             | no information about the base of the diff, but it is very
             | much _like_ applying a diff.
             | 
             | One way you can test this without drilling into source code
             | is to make two independent commit histories (using either
             | two git repos, or git checkout --orphan, or whatever) where
             | a commit in one history has a diff that would apply to a
             | file in the other history if applied with the "patch"
             | command. Then try cherry-picking it into the second
             | history. It should work.
             | 
             | (In the revert case, it more or less does the same thing,
             | just with "base" and "next" flipped. That is, if you have
             | commits A, B, and C, and you want to revert B, it does a
             | three-way merge where the base is the tree after B, one
             | side is the tree after A, and the other side is the tree
             | after C!)
        
               | mastazi wrote:
               | Wow this is very interesting, thank you for the
               | explanation
               | 
               | > "it applies a diff between a specified commit and its
               | parent on top of your current work"
               | 
               | this is in line with my intuitive understanding which was
               | based purely on usage.
        
               | martinvonz wrote:
               | Yep. Same thing in Jujutsu (the recursive merge is at htt
               | ps://github.com/martinvonz/jj/blob/a6ef792ba66b5b19e75282
               | ...). Probably the biggest difference compared Git there
               | is that it'll still work even if there are conflicts.
               | 
               | FYI, this is also how `jj undo` works, except that it's a
               | three-way merge at the repo level (https://github.com/mar
               | tinvonz/jj/blob/d9b364442e2246a734d600...). So that
               | applies changes to branches, checkouts (think: git HEAD),
               | and sets of anonymous heads. This is how you can undo an
               | operation even if it wasn't the most recent one (just
               | like you can `git revert` a commit that wasn't the most
               | recent one).
        
               | kazinator wrote:
               | It just sounds like, more or less:                   $
               | diff3 -m my-file pick-file-parent pick-file
        
             | mastazi wrote:
             | Yes, I agree about distant commits and turning it into a
             | patch.
             | 
             | Thank you for explaining the three-way merge between
             | baseline, commit and common ancestor, makes sense.
        
         | joseph8th wrote:
         | Emacs `magit` might qualify, if you don't mind first learning
         | Emacs
        
       | em-bee wrote:
       | jujutsu looks interesting, but one thing that i find missing from
       | git is historical branch tracking. once two branches are merged,
       | git does not tell me which series of commits used to belong to
       | which branch. i can't check out main from two weeks ago if a
       | merge happened in the meantime because that information is lost.
       | 
       | i fear to add such a feature additional information would need to
       | be stored in the git repo itself which would require a change to
       | git
        
         | Too wrote:
         | Git has the concept and knowledge of which side a merge came
         | from.
         | 
         | A commit having multiple parents (a merge commit) maintains the
         | order of those parents within the commit. The branch names are
         | famously lost, but by _convention_ you can say that the first
         | parent should always be the main branch.
         | 
         | As with all other git things, the ux for this feature isn't the
         | best and it's use varies wildly across tools and organizations.
         | 
         | To view the main branch log only you have to pass arcane
         | ---left-only flags into git log.
         | 
         | Some people don't know the difference of merging from branch to
         | main vs the other way around, end result looks the same right.
         | One such mistake messes up the history.
        
           | em-bee wrote:
           | that's the problem with git. it is powerful, but some things
           | are just not practical. if i have to be careful how i merge
           | then that's not user friendly. on the other hand, adding a
           | field that stores the name of the branch at commit time would
           | be almost trivial programmatically. and it would enable a
           | much more user friendly interface.
        
         | joseph8th wrote:
         | I don't need to repeat that Git has terrible UI, but you can
         | get this "history" with `git merge --no-ff <MYBRANCH>` (no
         | fast-forward).
         | 
         | In fact, it's a pretty common branch-based flow. Our team
         | pushes feature branches to remote, where they are vetted by QA,
         | and we have a chance for review.
         | 
         | When _pulling_ changes into _any_ branch, we always `git pull
         | --rebase`. When merging feature branches, we always `--no-ff`.
         | 
         | For small, local merges, we don't use `--no-ff` because it's
         | useless noise. But if someone forgets out of habit... Oh well.
         | I spend on average 0.000000001% of my time going through git
         | log. And when I do, I tell it to show as a tree
        
       | mberning wrote:
       | Congrats and good luck. Git desperately needs a radically
       | simplified and radically consistent set of porcelain interfaces.
        
       | cryptonector wrote:
       | > It combines features from Git (data model, speed), Mercurial
       | (anonymous branching, simple CLI free from "the index", revsets,
       | powerful history-rewriting), and Pijul/Darcs (first-class
       | conflicts), with features not found in either of them (working-
       | copy-as-a-commit, undo functionality, automatic rebase, safe
       | replication via rsync, Dropbox, or distributed file system).
       | 
       | You lost me at "free from the index". The index is one of the
       | most important parts of Git that makes _my_ life easier.
       | Opinionated DVCS UIs make my life harder -- all of them.
       | 
       | > The working copy is automatically committed
       | 
       | Right, so, the reason the index is powerful is that I get to do
       | `git add -e`, `git commit`, and repeat until I'm done or ready to
       | throw remaining changes away. I very much want the index /
       | workspace distinction.
       | 
       | > Automatic rebase
       | 
       | > Comprehensive support for rewriting history
       | 
       | This is very welcome. At the very least this confirms something
       | important: the fallacious argument that "rebase rewrites history,
       | so it's eeeevil" is finally dead.
        
         | throw0101a wrote:
         | > _You lost me at "free from the index". The index is one of
         | the most important parts of Git that makes my life easier.
         | Opinionated DVCS UIs make my life harder -- all of them._
         | 
         | Mercurial has an 'index' / staging area, but not exposed by
         | default. You can access it with some extra CLI options, but
         | there is an optional idea that may be 'better' and worth
         | looking into:
         | 
         | > _If you need the index, you can gain its behavior (with many
         | additional options) with mercurial queues [1] (MQ).[2] Simple
         | addition of changes to the index can be imitated by just
         | building up a commit with hg commit --amend (optionally with
         | --secret, see phases [3])._
         | 
         | * https://www.mercurial-
         | scm.org/wiki/GitConcepts#Git.27s_stagi...
         | 
         | [1] is "A Git User's Guide to Mercurial Queues"
         | 
         | * https://stevelosh.com/blog/2010/08/a-git-users-guide-to-
         | merc...
         | 
         | MQs (optionally) expand on the idea of only a single staging
         | area:
         | 
         | > _This single "intermediate" area is where git stops. For many
         | workflows it's enough, but if you want more power MQ has you
         | covered._
         | 
         | > _MQ is called Mercurial Queues for a reason. You can have
         | more than one patch in your queue, which means you can have
         | multiple "intermediate" areas if you need them._
         | 
         | If you only want to use one queue/index then that's fine too.
        
           | cryptonector wrote:
           | I find Mercurial very difficult to use. I find Git much
           | easier.
        
             | andrewshadura wrote:
             | It's just because you've been using Git for too long.
             | Mercurial is much easier to use if you're not exposed to
             | Git.
        
               | cryptonector wrote:
               | I used Mercurial before I used Git.
        
           | alwillis wrote:
           | As a Mercurial user from almost the beginning, it's not
           | accurate to say Mercurial has a hidden index.
           | 
           | That Steve Losh post is from 2010 and it was mainly
           | highlighting a workflow that was popular at the time for a
           | particular use case. It also highlighted how Mercurial's
           | plug-in architecture can be used to to support different
           | workflows.
           | 
           | Fast forward to the present and the use of MQ isn't really a
           | thing anymore, but is available for those who want it.
           | 
           | Check out https://octobus.net/blog/2020-11-26-modern-
           | mercurial.html for modern Mercurial practices.
        
         | [deleted]
        
         | yjftsjthsd-h wrote:
         | If you can rewrite the history that actually got committed, do
         | you really need a temporary pre-commit staging area?
        
           | bonzini wrote:
           | The index is mostly useful to me to split a commit in
           | multiple ones. You do that with a sequence of "git add -p"
           | and "git commit" commands. I am interested in how to do this
           | with jj, because otherwise it looks like a very interesting
           | tool.
        
             | erik_seaberg wrote:
             | I prefer "git stash -p" to exclude unfinished changes,
             | because if I build up a partial commit in the index there's
             | no way to test it.
        
               | cryptonector wrote:
               | I do that later. I do `git rebase -i` and add `exec`
               | lines to build each commit that must build.
        
             | cryptonector wrote:
             | `git add -e` is infinitely better.
        
             | andrewshadura wrote:
             | Try git-crecord.
        
             | masklinn wrote:
             | > You do that with a sequence of "git add -p" and "git
             | commit" commands.
             | 
             | You can do that with git commit -p.
        
               | bonzini wrote:
               | True but there's usually a "git diff --staged" in the
               | middle to check what I am committing.
        
               | masklinn wrote:
               | You can do that with "git show HEAD" (and "git commit
               | --amend -p").
        
               | cryptonector wrote:
               | Exactly!
        
             | martinvonz wrote:
             | > I am interested in how to do this with jj
             | 
             | `jj split -r <commit>`, where `<commit>` may be the working
             | copy commit (which is the default). See
             | https://github.com/martinvonz/jj/blob/main/docs/git-
             | comparis... for more examples.
        
               | detaro wrote:
               | so just for understanding: repeated `git add -p` followed
               | by a `git commit` turns into repeated `jj split; jj
               | squash`, since you create a commit each time?
        
               | martinvonz wrote:
               | That would work, yes, but there's also `jj squash -i` to
               | move part of the child commit into the parent. There's
               | also the more generic `jj move` command for moving part
               | of any commit into any other commit (ancestor,
               | descendant, sibling), so you `jj squash -i` is equivalent
               | to `jj move -i --from @ --to @-` (where `@` is syntax for
               | the working copy commit and `@-` is syntax for its
               | parents).
        
           | cryptonector wrote:
           | Yes, I do. I often do this (usually in detached HEAD mode!):
           | : ; $EDITOR some-file ...       : ; $build       : ; git add
           | -e # take a few chunks, maybe change them       : ; git diff
           | --staged; git status -uno       : ; # lather, rinse, repeat
           | : ; git commit -m '...' -ev       : ;        : ; git status
           | -uno; git diff       : ; git add -e # ..       : ; # lather,
           | rinse, repeat until happy       : ;        : ; git fetch
           | origin       : ; git rebase origin/master       : ; # fix any
           | conflicts       : ;        : ; # continue until all bug fix /
           | feature       : ; # activity for this issue is complete
           | : ;       : ; # review my changes:       : ; git log --patch
           | origin/master..       : ;       : ; # if I have to clean my
           | history a bit:       : ; git rebase -i origin/master       :
           | ; # re-order commits, `edit` commits, `drop`       : ; #
           | commits as needed       : ; $build       : ; # fix remaining
           | issues...       : ;        : ; # finally ready to push:
           | : ; git push myclone HEAD:refs/heads/this-thing       : ;
           | : ; # open a PR
           | 
           | Repeat as needed to deal with code review comments until done
           | and integrated.
        
             | c-smile wrote:
             | Are you human?
             | 
             | > detached HEAD mode
             | 
             | Ah, I see, not anymore...
        
               | cryptonector wrote:
               | Lol, have an upvote!
        
         | indygreg2 wrote:
         | The index is a power user feature. Its forced presence in Git
         | effectively constitutes a usability barrier for new users.
         | After all, a VCS is effectively a glorified abstraction for
         | "save a file." Any barrier imposed between changing a file and
         | committing it can get in the way and confuse people. The Git
         | index does this.
         | 
         | Furthermore, the index is effectively a pseudo commit without a
         | commit message. Any workflow using the index can be implemented
         | in terms of actual commits itself.
         | 
         | I think because Git doesn't have strong usability in general
         | and especially around history rewriting, many Git users feel
         | that the index or an index equivalent is somehow a required
         | feature of a VCS because Git's shortcomings give that illusion.
         | However, if you use a VCS with better history rewriting (such
         | as Mercurial with evolve), you'll likely come around to my
         | opinion that the index can be jettisoned without meaningful
         | loss of functionality or productivity.
        
           | cryptonector wrote:
           | I don't deny that the index is a power feature and that it's
           | difficult to explain it to newbies.
           | 
           | Perhaps there's room for new UIs.
           | 
           | All I'm saying is I need this power. And it has to be easy to
           | reach for it.
        
         | martinvonz wrote:
         | > You lost me at "free from the index".
         | 
         | If you click the link that text points you to (i.e.
         | https://github.com/martinvonz/jj/blob/main/docs/git-
         | comparis...), there's an explanation there for how to achieve
         | the same workflows. I get that it's _different_ , but I don't
         | think it's worse. I consider myself a (former) git power user
         | (I think I have ~90 patches in Git itself) and I've never
         | missed the index since I switched to Mercurial ~7 years ago.
         | 
         | > This is very welcome.
         | 
         | Thanks :)
        
           | omegalulw wrote:
           | > With Jujutsu, you'd instead use jj split to split the
           | working copy commit into two commits.
           | 
           | This is more confusing? Often times when debugging/writing a
           | fix I would have extraneous code that I wouldn't want to
           | commit. With an index I'm always sure if what I commit, but
           | with this workflow you have to keep track of such stuff all
           | the time and if you forget that stuff makes it in?
           | 
           | Not to mention that another benefit of an index is being able
           | to change commits and git replaying your working diff.
        
             | joseph8th wrote:
             | Yah... I have a long-standing habit of commenting `TODO`
             | for some debugging or WIP code. Then, before I commit, I
             | can just do `git diff | grep TODO` and see all the _new_
             | TODOs I 've added.
        
             | em-bee wrote:
             | yeah, i feel this is going to bother me, or at least be
             | difficult to get used to.
             | 
             | i often have temporary files that i do not want to commit,
             | nor do i want to add them to .gitignore (because i want to
             | commit them later)
             | 
             | but then, i'll have to spend some time using jj split. if
             | it is powerful enough then maybe the end result is just
             | that those files only live in the last commit.
             | 
             | also, what happens on push? i'd never ever want the working
             | copy to be pushed to the remote repo. i could not find
             | anything in the documentation about that.
             | 
             | (according to the answer here:
             | https://news.ycombinator.com/item?id=30399554 the working
             | copy is not supposed to be pushed)
        
           | cryptonector wrote:
           | You cover `git add -p`, but I want `git add -e`.
           | 
           | Also, I often rebase and `edit` commits to split them or undo
           | parts of them.
           | 
           | Rebase and all this is all about making commits that have
           | just the right content, and keeping history clean and linear.
           | The tools have to make this possible and easy.
           | 
           | I get that git feels... barebones for this. You really have
           | to understand what you're doing when using git like I do, so
           | I get that it's not very accessible.
           | 
           | Better UIs are great, but on the other hand, we need to be
           | able to get down to the low level.
           | 
           | IMO.
        
             | martinvonz wrote:
             | > You cover `git add -p`, but I want `git add -e`.
             | 
             | Interesting. I don't think I've heard anyone use `git add
             | -e` before. It should be easy to add that feature, but it
             | would be very low priority since so few users seem to like
             | to manually edit patches.
             | 
             | > Also, I often rebase and `edit` commits to split them or
             | undo parts of them.
             | 
             | You can do that by checking out the commit, then `jj
             | squash/amend` (aliases) and all descendants will be
             | automatically rebased on top, and branches pointing to them
             | will be updated too. There's also `jj edit` for editing the
             | changes in a commit without updating to it. And there's `jj
             | split` for splitting a commit (without needing to update to
             | it).
             | 
             | > Rebase and all this is all about making commits that have
             | just the right content, and keeping history clean and
             | linear. The tools have to make this possible and easy.
             | 
             | Yes, that's definitely a goal. I think Jujutsu does a much
             | better job at that than Git does. Did you read
             | https://github.com/martinvonz/jj#comprehensive-support-
             | for-r...?
        
               | cryptonector wrote:
               | I did, and it's almost certainly nicer than Git for
               | commit splitting.
               | 
               | But even though I might use a tool specifically designed
               | for user-friendly commit splitting, I still want: `git
               | add -e`, `git diff --staged` (to see what I added with
               | `git add -e`) vs `git diff` (to see what I left out), and
               | `git commit` w/o `-a` to commit the contents of the
               | index. This is easier for me than `$WHATEVER commit`
               | followed by `$WHATEVER`'s commit splitting method.
               | 
               | That said, I have to congratulate you again on not taking
               | the ugh-rebase-rewrites-history/history-rewrite-bad road.
               | This is a huge step forward for DVCS.
               | 
               | It may well be that what rebase workflows needed was a UI
               | that non-power users could use.
               | 
               | While we're at it, I wonder what you think of this: https
               | ://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee650..
               | .
        
               | martinvonz wrote:
               | That gist seems like a simplified version of
               | https://github.com/mhagger/git-imerge, so check that out
               | if you haven't. (I haven't looked at git-imerge in a long
               | time, so I should read about it again myself.)
        
           | alwillis wrote:
           | Something that's backend compatible with Git but uses some of
           | Mercurial's sensibilities?
           | 
           | Sign me up!
        
             | buck4roo wrote:
             | https://hg-git.github.io/
             | 
             | Happy user for at least 6 years.
             | 
             | The sanity of Mercurial's UX cannot be overstated.
        
         | dilap wrote:
         | I like and use the index in git too, but I wouldn't be so quick
         | to dismiss other models that might end up solving the same use
         | cases in a different way...
         | 
         | From the README, it looks like there's robust support for
         | editing and splitting commits. So maybe in practice the flow is
         | similar to using the index, with the added the added benefit
         | that your work is backed via commits along the way, and the
         | simplicity of not having the index as an extra concept.
         | 
         | In general when exvaluating X from the perspective of Y, we
         | will immediately see the thing's about Y we like that X lacks;
         | it takes more time to see if perhaps in the fuller context of X
         | those things are not necessary.
        
         | masklinn wrote:
         | > Right, so, the reason the index is powerful is that I get to
         | do `git add -e`, `git commit`, and repeat until I'm done or
         | ready to throw remaining changes away.
         | 
         | You don't need the index for that. In fact I'd say it gets in
         | the way because the presence of the one means less pressure on
         | improving the ability to edit commits: while it's easy to add
         | stuff to HEAD it's much more painful to remove content from it.
         | 
         | If that is solved, then the value of the index drops
         | precipitously, because you can create a commit with a purpose
         | and select its content instead of having to do it the other way
         | around then forgetting what change you were trying to craft.
        
       | [deleted]
        
       | ArtixFox wrote:
       | oh cmon u cant trick me like that! i thought jujutsu kaisen was
       | on hn
        
       | user-the-name wrote:
       | I can't find it mentioned anywhere, but does jj support
       | submodules? And does it make them actually work, unlike the
       | broken mess git has?
       | 
       | This is the biggest thing keeping me using mercurial, the fact
       | that it has subrepos that work.
        
         | iveqy wrote:
         | What do you think is broken with git submodules?
        
           | user-the-name wrote:
           | Everything? The default state after checking out a git
           | project with submodules is for them to be in the wrong state!
           | Keeping the state of submodules and the main repo in sync is
           | a complete shambles.
           | 
           | Try mercurial to see how to do it correctly.
        
       | joshuamorton wrote:
       | Am I right to say that the working-copy-as-commit and undo-
       | functionality features are inspired by piper? Mighty neat to see
       | those make it to a normalish vcs.
        
         | martinvonz wrote:
         | I'm not sure if I'm allowed to say whether Piper has those
         | features, but since you seem to be a Googler, you probably know
         | (or can find out) :)
         | 
         | I suppose I can still tell you that the features were not
         | _inspired_ by Piper without revealing whether Piper has them :)
        
       | jjthrowaway wrote:
       | It would be nice if this were in nixpkgs, it's a pain to manage
       | all the different language environments and it would save me from
       | trying to get it to compile.
       | 
       | Right now                   error[E0554]: `#![feature]` may not
       | be used on the stable release channel       -->
       | lib/src/lib.rs:15:12        |
       | 
       | 15 | #![feature(assert_matches)] |
        
         | gmfawcett wrote:
         | If you get it working, please share a flake. :)
        
           | martinvonz wrote:
           | I filed https://github.com/martinvonz/jj/issues/61 about
           | having Nix packages. I should learn about Nix packaging some
           | day, but I'd appreciate any help I can get.
        
             | martinvonz wrote:
             | FYI, there was an update on that issue saying that they're
             | going to create an overlay tomorrow.
        
               | gmfawcett wrote:
               | Awesome! Thanks for sharing the update.
        
       | kuboble wrote:
       | 1) What are the advantages of using native backend as compared to
       | git?
       | 
       | 2) Are there any potential issues one has to be aware of when
       | using jj contributing to git repository?
       | 
       | I remember when I was the only team member using git-svn plugin
       | my coworkers were confused when I svn-committed many commits at
       | once with some of them breaking the time order of the svn history
       | (as git-svn commits in svn were recorded with git timestamp and
       | not the actual svn- commit timestamps)
        
         | martinvonz wrote:
         | > 1) What are the advantages of using native backend as
         | compared to git?
         | 
         | Very few. The disadvantages are generally much larger. The main
         | advantage is that you won't run into a (harmless) race that
         | happens once in a while with the git backend
         | (https://github.com/martinvonz/jj/issues/27). Disadvantages
         | include not being able to interact with git repo and
         | performance problems (both size and speed).
         | 
         | I should add a note about this to the README.
         | 
         | The backend exists mostly to prove that it's possible and to
         | make sure that the backend API doesn't become tied to Git.
         | 
         | > 2) Are there any potential issues one has to be aware of when
         | using jj contributing to git repository?
         | 
         | The main one is that you should avoid pushing commits with
         | conflicts. It won't corrupt the remote repo, but git clients
         | won't know what to do with the conflicted files. The fix is to
         | fix the conflict and force push the conflict-free commit.
         | 
         | I'll file a bug to prevent pushing commits with conflicts.
        
           | Aeolun wrote:
           | > git clients won't know what to do with the conflicted files
           | 
           | This seems kind of similar to pushing git files with
           | conflicts with the git client? Maybe the Jujutsu formatting
           | is slightly different, but the concept is the same.
        
             | martinvonz wrote:
             | These are representations of conflicts that are stored as
             | special files, they are not regular files with conflict
             | markers in. If you look at the commit with regular `git`,
             | you're going to see a weird file with some JSON in it.
        
               | Aeolun wrote:
               | That's arguably better ;) thanks for the explanation.
        
           | hinkley wrote:
           | > The backend exists mostly to prove that it's possible and
           | to make sure that the backend API doesn't become tied to Git.
           | 
           | Do you expect this to always be the case or are you waiting
           | for inspiration/collaboration to make a better go of it?
        
             | martinvonz wrote:
             | I hope to one day make it better, but it's very low
             | priority right now because the Git backend works well and
             | has the big advantage that it's compatible with Git :) Also
             | see https://news.ycombinator.com/item?id=30403737.
        
           | krick wrote:
           | If we ignore the UI level stuff, like doing something by
           | default when you switch to another branch, etc -- is it in
           | any way "smarter" than git? For example, are there
           | situations, when I couldn't reorder my commits when doing git
           | rebase -i without resolving some conflicts manually, while jj
           | would be able to correctly handle them for me?
        
             | martinvonz wrote:
             | Yes and no. For example, if you reorder two commits, the
             | new child commit will never have conflicts even if the
             | parent had conflicts. That's because the changes from both
             | original commits still apply afterwards. Similarly, if you
             | rebase a commit and it results on conflicts, you can then
             | rebase it back and the conflicts will go away. See the demo
             | at https://asciinema.org/a/HqYA9SL2tzarPAErpYs684GGR
        
       | swagonomixxx wrote:
       | > A Git-compatible DVCS that is both simple and powerful
       | 
       | We all know the dig here - Git is not simple.
       | 
       | Like many tools, Git has evolved significantly over the years.
       | Git today was not like Git 10 years ago.
       | 
       | Also, like many replacements to existing tools and software, they
       | always start out simple and beautiful. Then they grow in
       | complexity to serve the domain. The reason Git is complicated -
       | not "simple" - is mostly because version control _is_ complex.
       | 
       | I also don't agree that Git is hard to use. I feel it is an odd
       | goal to try to make everything - even tools that experts use -
       | simple to use, when they are fundamentally not simple. I feel
       | like Git is sufficiently complex - no more than it needs to be
       | and certainly not less.
        
         | hinkley wrote:
         | I am by all accounts the SME on git at my company. I often am
         | the VCS expert at my company. I don't like using tools I don't
         | understand, and my brain is pretty good at handling problems
         | that look like graph theory.
         | 
         | After using git for 6 years git still terrifies me. After 9
         | months of svn I performed open heart surgery to remove a 1GB
         | zip file that some dummy merged before anyone thought to stop
         | him. It was at least 18 months before I tried something similar
         | with git and I made copies of my copies to make sure I didn't
         | fuck it up. And I still almost needed a do-over.
         | 
         | The level of dread I have using git is pretty close to how I
         | feel when using a newly sharpened chef's knife -
         | hypervigilance. And that feeling gets stronger when I hand that
         | knife to someone else. Be very careful, that's super sharp...
         | hold still, I'll get you a bandaid. Now you get a mini lecture
         | on how to hold a knife without cutting yourself next time.
        
           | tragictrash wrote:
           | It's not that hard man. Really isn't. Your anecdote sounds
           | like someone who thinks they're awesome at git setting a noob
           | up for failure and then mansplaining when they fuck up.
           | 
           | It's not hard to be better at git than 85% of people, most
           | devs I've met don't understand the basics beyond pull commit
           | push.
        
             | hinkley wrote:
             | You don't get to work on a git repository by yourself.
        
             | chrismorgan wrote:
             | It must be admitted that _if merges are involved_ , it
             | becomes somewhat harder to do something like this, as you
             | can no longer use the easy and safe path of an interactive
             | rebase to edit the commit and remove the file, and must
             | reach for filter-branch or similar, which are generally a
             | good deal scarier and easier to make difficult-to-identify
             | mistakes with. (Fortunately, the man page git-filter-
             | branch(1) deals with this specific case as its first
             | example.)
             | 
             | But it's certainly not the easiest thing to mess up a Git
             | repository to the point of losing data; the reflog keeps it
             | all intact for at least a month unless you very
             | deliberately tell it not to (see the "CHECKLIST FOR
             | SHRINKING A REPOSITORY" section of git-filter-branch(1) for
             | sample invocations after such an edit), and I'd be much
             | more comfortable about open heart surgery on Git's model
             | than on SVN's.
        
               | hinkley wrote:
               | Almost all of the complexity of VCS is in or around
               | merges. Take away accidental complexity and there is a
               | lot of inherent complexity in merges.
               | 
               | First git project we had a guy who was bad at merges, and
               | his solution was to avoid them as long as he could, which
               | just made things worse. He also disliked another
               | engineer. That engineer was definitely making mistakes
               | but at the end of the day his Dunning Krueger was causing
               | me less trouble than merge boy's. Also suspect a little
               | ageism, but would not have been able to defend that
               | suspicion.
               | 
               | So one day merge boy was loudly exclaiming that old guy
               | had written a terrible bug and the hit history proved it.
               | Only the bug in question was something I specifically
               | looked for in the code review, and had been happy to find
               | that he had gotten it right. But here in git annotate it
               | shows he got it wrong. What the hell?
               | 
               | So I step through the commit history one commit at a
               | time, sure enough the code was initially correct... until
               | merge boy did a merge and fucked up the three way. Again.
               | And got old guy's name to show up in annotate. I didn't
               | even know you could do that.
        
         | martinvonz wrote:
         | > I feel like Git is sufficiently complex - no more than it
         | needs to be and certainly not less.
         | 
         | Perhaps the biggest mistake (IMO) was to expose the index to
         | the user. I happened to just watch
         | https://www.youtube.com/watch?v=31XZYMjg93o (by the person
         | behind Gitless). They explain the issues well there.
        
           | hinkley wrote:
           | > They told me offline use was a big advantage of git over
           | svn. But, how are you supposed to use git without Google?
           | 
           | Shots fired.
        
           | KerrAvon wrote:
           | I haven't watched that video, but I agree -- the index is one
           | of the biggest hurdles to making git easy to understand and
           | use for newcomers. It's not hard to explain the fundamental
           | model of how git works -- it's hard to explain the UI, and
           | it's hard to explain the index. If you remove the index,
           | you're only working with commits, and that simplifies the UI
           | enormously.
        
           | hinkley wrote:
           | I'm gonna watch this video. What's been bugging me for a long
           | time, as someone who didn't quite get to see all of the
           | supposed ugliness of Subversion (which by description alone
           | sounds an awful lot like the rerere situation with Git, which
           | I have).
           | 
           | It really feels to me like a commit identifier should be the
           | combination of a monotonically increasing number and a hash
           | of the content, rather than an either-or. If I merge or
           | rebase branches in git, I lose the index, just as I would in
           | subversion. But at least in svn I have some notion of how far
           | back commit 12345 is in the tree. ac4def2 could be HEAD or
           | four years ago.
        
       | mstaoru wrote:
       | Great work! Just FYI, in Chinese JJ is a way to refer to male
       | reproductive organs.
        
       | dark-star wrote:
       | git is already very simple, at least for the 95% of use-cases
       | that I need. add, commit, checkout, push, pull.... maybe a branch
       | and merge here and there, but that's it.
       | 
       | Of course I cannot remember how exactly the "git rebase" command
       | works and have to look it up every time, same as all those
       | switches to the "simpler" commands.
       | 
       | I guess it all depends on what you need. Python looks really
       | complicated too, if you start by browsing the function and class
       | reference. But for someone starting to learn programming, it is
       | apparently pretty easy (or so I've heard)
        
       | freedomben wrote:
       | This looks like an interesting project, and I'm glad that people
       | are still thinking about how to improve on version control.
       | 
       | That said, building a version control system seems like a problem
       | similar to a social network: the network affect causes an
       | enormous amount of friction. i.e. most people don't want to use
       | it until other people are using it. A vicious cycle.
       | 
       | The fact that it's compatible with git as a backend is really
       | great though, and is probably the key to driving adoption.
       | However I have several immediate thoughts that come to mind that
       | cause me hesitancy. Answers in the README.md would be super
       | helpful for marketing to me (and deep apology if it's there and I
       | missed it):
       | 
       | 1. How does it look to _others_ working on the repo using just
       | git? For example,  "when the working copy is automatically
       | committed," where does it go? is there a remote branch that
       | someone could see if they `git fetch` while I'm working? I often
       | put all sorts of things in the code that I don't want to have
       | committed, ranging from harmless (a bunch of personal comments or
       | `IO.puts()`), to very important (API keys and such that I'm
       | testing with. I always move them to env vars before committing
       | but for first-pass testing to prove the concept I "hardcode" them
       | at first).[1]
       | 
       | 2. Similar to "how does it look to others," what sort of burden
       | does "all operations you perform in the repo are recorded, along
       | with a snapshot of the repo state after the operation" put on the
       | git backend? If I'm hacking on an ffmpeg script and I
       | (temporarily) copy a 4GB mp4 file into the working directory so I
       | can easily run `./mycode video.mp4`, does that whole thing get
       | committed, potentially every time it changes? That could easily
       | turn into a 40GB set of changes.[1]
       | 
       | 3. Do you _have_ to use the jj backend to get all the feature?
       | For example, with a git backend could you get the two things
       | mentioned above and also  "Conflicts can be recorded in commits"
       | as well?
       | 
       | A quick section in the README.md about which features require the
       | jj backend instead of git would be super helpful, and if written
       | well could answer all of the questions above.
       | 
       | To sum up my comment in a TL;DR: To really sell me on a project
       | like this it has to work with git, and being able to quickly tell
       | which features I can use _with git_ , would make this
       | substantially more interesting to me.
       | 
       | [1]: Related: https://xkcd.com/1172/
        
         | martinvonz wrote:
         | > For example, "when the working copy is automatically
         | committed," where does it go?
         | 
         | It becomes a regular git commit with a git ref called something
         | like `refs/jj/keep/9f1a0fb0-a0aa-4a4b-922f-d6d48687996a`
         | pointing to it (to prevent GC). It won't get fetched or pushed
         | by default, except with `--mirror`, I think.
         | 
         | > If I'm hacking on an ffmpeg script and I (temporarily) copy a
         | 4GB mp4 file into the working directory so I can easily run
         | `./mycode video.mp4`
         | 
         | Yes! You'll have to more diligent about keeping your .gitignore
         | (or .git/info/exclude, etc) file updated. I plan to add
         | commands for fixing such mistakes by forgetting the commit.
         | 
         | > Do you have to use the jj backend to get all the feature?
         | 
         | Nope, conflicts work with the git backend as well.
         | https://github.com/martinvonz/jj/blob/main/docs/git-compatib...
         | has some info.
         | 
         | > To sum up my comment in a TL;DR: To really sell me on a
         | project like this it has to work with git, and being able to
         | quickly tell which features I can use with git, would make this
         | substantially more interesting to me.
         | 
         | Makes sense. Thanks for the suggestion! I'll put it on my TODO
         | list.
        
           | freedomben wrote:
           | Awesome, thanks for the answers and thanks for sharing your
           | project! I'll give it a try :-)
        
       | skrebbel wrote:
       | Wow, this scratches a lot of my itches about Git. I teach a Git
       | course at my alma mater, and the things that confuses people the
       | most (the index, how to undo mistakes etc etc) all seem addressed
       | head-on. At first glance, this seems substantially easier to
       | teach than Git.
       | 
       | The Git compat seems like a great idea for this to really take
       | off. My team is totally PR based though so if/when doing (Git
       | compatible) feature branches lands in JJ I'm excited to switch.
        
         | Aeolun wrote:
         | I'm not sure I understand how you can have a git compatible
         | data store, but not have git compatible feature branches?
        
           | martinvonz wrote:
           | I don't think skrebbel was saying that the branches are _not_
           | git-compatible, I think they were just wondering if there is
           | support for branches at all, but I 'm not sure. Anyway, there
           | is support for branches. They behave more like Mercurial's
           | "bookmarks" in that they are assumed to have the same name on
           | all remotes. That usually works well, but it gets annoying if
           | there are unrelated branches all called e.g. "fix-formatting"
           | on multiple remotes you pull from. Jujutsu would then tell
           | you that the branch has a conflict because it doesn't know
           | where it's supposed to point. I'll probably add some way of
           | telling `jj git fetch` which branches to import, but I'm not
           | sure yet what the best solution is.
           | 
           | See
           | https://github.com/martinvonz/jj/blob/main/docs/branches.md
           | for more information.
        
         | wcarss wrote:
         | > My team is totally PR based though so if/when doing (Git
         | compatible) feature branches lands in JJ I'm excited to switch.
         | 
         | I'm trying to find the part of the docs that refers to this
         | functionality as missing but I can't -- does jj not have the
         | ability to create, update, pull from, merge branches, etc?
        
           | intrepidhero wrote:
           | > For example, pull-request workflows currently require too
           | many manual steps.
           | 
           | Supported but not great I guess?
        
             | martinvonz wrote:
             | Yes, they are supported, and documented at https://github.c
             | om/martinvonz/jj/blob/main/docs/branches.md. I need to
             | document better how to use them for common workflows like
             | GitHub PRs.
             | 
             | FYI, here's one way to use them with GitHub PRs:
             | 
             | 1. Create a fork via GitHub's web UI 2. Clone using the SSH
             | protocol (`jj git clone git@github.com:...`) 3. Make your
             | changes and "commit" (`jj close/commit`) 4. Create a branch
             | pointing to the commit you just created (`jj branch my-
             | feature -r @-`) 5. Push it to your fork (`jj git push`)
             | 
             | So that doesn't seem too onerous, I guess? Maybe the "too
             | many manual steps" are to clean up afterwards. I just tried
             | it in a test repo and deleting the branch from the fork and
             | then `jj git fetch` from there does delete the local
             | branch, but it doesn't abandon the commits, so you need to
             | run `jj abandon` on them if you don't want them anymore.
        
         | stouset wrote:
         | While I agree that git could use a rethink from a user tooling
         | perspective, I _really_ appreciate the existence of the index.
         | I'm not tied necessarily to this specific implementation of it,
         | but having a staging area where chunks are added piecemeal is
         | an enormous benefit.
         | 
         | I honestly wish git forced `-p` for operations that support it.
         | I've worked on too many teams where people would just commit
         | everything in their working directory, and it would inevitably
         | make reviewing their PRs a nightmare. Particularly with times
         | where changes were accidentally committed wholesale that
         | shouldn't have been part of that set of changes.
        
           | skrebbel wrote:
           | I'm not opposed to carefully crafting a good commit, I'm
           | opposed to a state-heavy, badly named, inconsistent feature
           | to do it. And if you use any decent git UI (including -p on
           | the CLI), you don't really need it to be that persistent very
           | often. It could just be a list of chunks to select in the
           | "make commit" window, which is of course exactly how most git
           | UIs "make commit" window looks. It's a single step then, no
           | intermediary persistent state (with three names).
           | 
           | JJ seems to workaround this in the other direction, by making
           | the concept of commits and rebases much more lightweight,
           | which i think is a refreshing enough take that I'd like to
           | try it.
        
           | Hendrikto wrote:
           | > I've worked on too many teams where people would just
           | commit everything in their working directory, and it would
           | inevitably make reviewing their PRs a nightmare.
           | 
           | And they always claim to review and clean their commits
           | before pushing, or at least before merging, but never do.
        
           | pjc50 wrote:
           | > just commit everything in their working directory
           | 
           | But that's what they've tested. I've had far more problems in
           | the other direction, where the commit doesn't contain the
           | complete set of things that it's supposed to but because all
           | the tooling - every single IDE and compiler - is looking at
           | the working directory not the index, I've missed something.
           | 
           | The index is _definitely_ confusing for new users and users
           | of other VCS.
           | 
           | > having a staging area where chunks are added piecemeal is
           | an enormous benefit.
           | 
           | It would be quite fun if we could have hierarchical commits,
           | so I could add bits to a commit without having to
           | squash/amend. Then you'd see the top-level work item as a
           | "commit" and the individual changes as "subcommits".
        
             | stouset wrote:
             | Like I said, I'm not sold on git's specific implementation.
             | But breaking things into smaller, focused commits is--in my
             | experience--a hallmark of good development practice.
             | 
             | There should absolutely be better tooling around it, so
             | that these piecemeal commits can be tested in isolation
             | from one another. That's a far better approach than just
             | throwing up our hands and committing everything in the
             | working tree, even if half of it has nothing to do with
             | what's intended.
        
               | treadmill wrote:
               | How do you even end up in that situation? If you start a
               | new feature or bugfix having random local changes lying
               | around, you are _already_ doing it wrong. Start a feature
               | branch, do clean commits of the current state, test,
               | push, review, merge.
        
               | jefftk wrote:
               | jj split?
        
               | pjc50 wrote:
               | > if half of it has nothing to do with what's intended.
               | 
               | Perhaps the focus should then be on making it easier to
               | get that junk out of the working tree? Better stashing?
        
             | throw0101a wrote:
             | > _It would be quite fun if we could have hierarchical
             | commits, so I could add bits to a commit without having to
             | squash /amend. Then you'd see the top-level work item as a
             | "commit" and the individual changes as "subcommits"._
             | 
             | Would something like Mercurial's queues be something what
             | you're looking for?
             | 
             | * https://stevelosh.com/blog/2010/08/a-git-users-guide-to-
             | merc...
             | 
             | See especially "...with Two (or More) Patches" onwards.
        
             | feanaro wrote:
             | > But that's what they've tested.
             | 
             | https://pre-commit.com/ helps with that.
             | 
             | > It would be quite fun if we could have hierarchical
             | commits, so I could add bits to a commit without having to
             | squash/amend.
             | 
             | Yes! I've been saying this for years.
             | 
             | Branch merge commits are already this, kind of. However
             | their UI sucks and there's an idea gap which prevents them
             | from being fully understood as such "supercommits" composed
             | of subcommits.
             | 
             | For one, the user should be forced to give meaningful, high
             | level commit messages for merge commits and the tooling
             | should fold commits made on a merge branch into the merge
             | commit by default (effectively linearizing the merged
             | history).
        
               | CRConrad wrote:
               | >> hierarchical commits, so I could add bits to a commit
               | without having to squash/amend.
               | 
               | > Branch merge commits are already this, kind of. However
               | their UI sucks and there's an idea gap which prevents
               | them from being fully understood as such "supercommits"
               | composed of subcommits.
               | 
               | Isn't that "idea gap" mainly the fault of all these weird
               | newfangled git workflows that discourage or outright
               | forbid branching? If you have no branches to merge, you
               | can't have a merge commit to act as a "supercommit".
               | 
               | Call your "supercommit" a "feature", and what you need to
               | implement it is... A feature branch.
        
               | usrusr wrote:
               | The history graph not presented as a list but as a
               | collapsible tree, sounds good! Might need a change in
               | merge commit message culture though, or more: in the
               | workflows I have experienced, the best time for writing
               | the message you'd see on the collapsed presentation would
               | be branch time, not merge.
               | 
               | Ideally you'd have a data model that keeps a "what is
               | this" description for branches that can be updated as
               | long as the branch lives and that gets moved to the
               | commit message on merge. Could this be done with some
               | combination of convention and hooks? I guess a file in
               | the root that is always kept on target/into branch state,
               | with the lost file content of the source/from branch
               | moved to the commit message would be all that's needed?
        
         | soheil wrote:
         | I think a lot of git is overkill for what most people use it
         | for it. It's time for a new tool to do these basic operations
         | push/pull/undo/redo. Branching is helpful, but if you work in a
         | relatively small codebase a tool that did _cp -r_ under the
         | hood would work perfectly 99% of times.
        
       | rhabarba wrote:
       | Finally! Another VCS!
        
         | johnmaguire wrote:
         | I think the network effect that Got has is one of the biggest
         | reasons no other VCS has succeeded at user adoption in recent
         | years.
         | 
         | By allowing a Git backend to use the Jujutsu frontend it could
         | develop a following.
        
       | hinkley wrote:
       | "Powerful" has become to me a shibboleth for people who are full
       | of it.
       | 
       | I can't recall the last time a coworker who liked things because
       | they were powerful didn't end up being untrustworthy. Even
       | dangerous. It's like nobody remembers the Principle of Least
       | Power.
       | 
       | That said, I will take someone obsessed with "powerful" over
       | "flexible" any day of the week.
        
         | kjeetgill wrote:
         | Hm, I guess for tools like this I always read "powerful" _as_
         | "flexible" - as in: this tools has strictly more
         | power/capabilities making it more flexible. In terms of "dev
         | tool marketing speak" I guess it's the opposite of "robust"
         | meaning: fewer features that are less likely to break on you.
        
           | hinkley wrote:
           | The only flexible tool I use in the real world is the
           | Leatherman, and that's for situations when I don't know what
           | I'll need, or if I'll need it. For every other task I have a
           | tool that is designed (sometimes quite well) for a set of
           | tasks that includes the one at hand (see also Alton Brown, no
           | single-purpose tools).
           | 
           | The Leatherman is part of my EDC, along with an LED
           | flashlight with some respectable lumens so I don't have to
           | use my phone to see in the dark.
           | 
           | In software this is known as the Unix Philosophy, but we
           | violate it quite often, and call those tools 'powerful' or
           | 'flexible'. Everything is a Swiss Army Knife all the time,
           | and we aren't self-aware enough to see how consistently - and
           | sometimes badly - we struggle with this.
           | 
           | But you can't tell an addict they're an addict. They will
           | fight you to the death about how they Don't Have a Problem.
        
       | mdaniel wrote:
       | That's quite impressive, congratulations!
       | 
       | The git comparison docs have:
       | 
       | > Start working on a new change based on the <main> branch -- jj
       | co main
       | 
       | Did you consider the recent git nomenclature change to use
       | "switch" for branch operations, and "co" for file operations? I
       | actually can't tell from so deep in my "git Stockholm syndrome"
       | whether that distinction is really hard on new users or not, but
       | the fact that git expended the energy meant they thought it was
       | meaningful
       | 
       | And, do you have plans on supporting signed commits, either via
       | gpg or the newfound SSH key signing?
       | 
       | I'm super excited to try out the conflict resolution mechanism,
       | because that's a major painpoint for my long-lived PR branches
        
         | martinvonz wrote:
         | Thanks!
         | 
         | > Did you consider the recent git nomenclature change to use
         | "switch" for branch operations, and "co" for file operations?
         | 
         | Actually, isn't "restore" for file operations? My impression
         | was that everyone agrees that `git checkout` does too many
         | different things. In particular, it's both for switching
         | branches and for restoring file content. So they added the new
         | `git switch` and `git restore` with limited scope. I strongly
         | suspect that they would have used `git checkout` for the former
         | if that wasn't already taken by the existing command.
         | 
         | > And, do you have plans on supporting signed commits, either
         | via gpg or the newfound SSH key signing?
         | 
         | No, that's not something I've even started thinking about. I'll
         | have to read up on how it works in Git first. Patches welcome,
         | though :)
         | 
         | > I'm super excited to try out the conflict resolution
         | mechanism, because that's a major painpoint for my long-lived
         | PR branches
         | 
         | You mean so you can continuously rebase them without having to
         | resolve conflicts right away? Yes, that's one of the benefits
         | of first-class conflicts. Another benefit, which took me a long
         | time to realize how useful it is, is the auto-rebase feature.
        
           | mdaniel wrote:
           | > No, that's not something I've even started thinking about.
           | I'll have to read up on how it works in Git first. Patches
           | welcome, though :)
           | 
           | I opened an issue and provided links to the docs, and a link
           | to the current way that git implements it:
           | https://github.com/martinvonz/jj/issues/58
           | 
           | As I was trying to find the correct command in jj for where
           | to add the new argument, I realized that this may not play
           | nice-nice with jj's commit-everything model, so I'm actually
           | prepared for the issue to be closed WONTFIX :-)
           | 
           | As for the patches welcome part, I notice that the Google CLA
           | bot is on your repo. While I do have the CLA signed for my
           | Gmail address, it seemed like some major tomfoolery to try
           | and add my current github email address (and the one which
           | backs my GPG key, to bring this full circle!) to the existing
           | CLA process. Do you intend to keep that CLA mechanism in
           | place, or was it just an oversight?
        
             | martinvonz wrote:
             | > I realized that this may not play nice-nice with jj's
             | commit-everything model
             | 
             | Yes, I suppose you might not want to sign every working
             | copy commit, but as you noted on the issue, it would
             | probably make sense on `jj close/commit` (aliases).
             | 
             | > Do you intend to keep that CLA mechanism in place
             | 
             | I started working on this project internally and then open-
             | sourced it. I don't think I'm allowed to remove the CLA
             | bot. I understand that it's annoying :(
        
           | smichel17 wrote:
           | I had a discussion about the git cli UX around
           | branching/stashing/checkout a while back. Perhaps you'll find
           | it useful: https://news.ycombinator.com/item?id=23807410
           | 
           | (I post this somewhat selfishly, as I'm basically describing
           | how I wish git worked ;)
        
       | CGamesPlay wrote:
       | Interesting ideas! I especially like the automatic rebasing and
       | associated ideas.
       | 
       | It's a bit strange to see "jj st" will automatically add all
       | files to the "working copy" commit. This means that when I
       | initially create my project, run "npm install" to install 500 MB
       | of dependencies, and then run "jj st" to figure out what to
       | include in my first commit, the command is going to copy all of
       | that into a commit object for no reason. I don't think I like
       | that behavior, to be honest. Is this a requirement of any of the
       | other unique features? Could this be turned off, or modified to
       | be an explicit operation?
       | 
       | [append]
       | 
       | To be clear, the fact that it's `jj st` is actually a big part of
       | the problem for me: this is the command I use to figure out what
       | to put into my `.gitignore` in the first place! I don't think
       | that any of the "read-only" commands should be making these kind
       | of changes.
        
         | brigandish wrote:
         | In this case, a global .gitignore would be a help (or something
         | like Yarn's plug n play?). I know that it doesn't really
         | address what you're pointing to here, I can see what you're
         | saying.
         | 
         | Perhaps that's a good time to use the undo operation.
        
         | bitcharmer wrote:
         | Why put 500mb worth of downloadable dependencies in your source
         | tree? This sounds like a terrible thing to do.
        
           | rileymat2 wrote:
           | Have used node.js, I find this, conceptually, much more
           | simple to trace through than search paths.
           | 
           | Of course there are major cons.
        
           | Too wrote:
           | This is the default behavior of npm. The most popular package
           | manager on the planet.
           | 
           | It might not be technically the most superior way to do
           | things, but given the widespread use, tooling around it need
           | to be compatible.
        
             | IceDane wrote:
             | It puts those deps in your source tree, sure, but no one
             | advocates committing them to your repository except in few
             | specific scenarios.
             | 
             | This kind of thing is also pretty much standard for most
             | programming languages today.
        
               | bitcharmer wrote:
               | > This kind of thing is also pretty much standard for
               | most programming languages today
               | 
               | No, it is not. Have a look at java, golang or rust. None
               | of those languages advocate for embedding deps in your
               | source tree as it's quite clearly a terrible anti-pattern
               | to follow.
               | 
               | I wouldn't consider how JavaScript does stuff a good
               | example.
        
               | Too wrote:
               | Isn't parent explicitly trying to avoid committing the
               | node_modules?
        
               | IceDane wrote:
               | It seems to me bitcharmer was railing against the notion
               | that you would have X MB of dependencies in your project
               | folder. I was just pointing out that this is basically
               | standard practice today(and the alternatives are usually
               | awful) and that even if you do have your deps in the
               | project folder, you don't usually check them into version
               | control, so his entire point is moot.
        
           | baq wrote:
           | 500 MB may be excessive for git, but it is a good practice to
           | check in your compiler together with your source if you use
           | perforce. It's just an extreme case of monorepo.
        
           | cudgy wrote:
           | Why have 500mb of dependencies if they dwarf your app and are
           | too large to have in your source tree?
        
       | giovannibonetti wrote:
       | > The command-line tool is called jj for now because it's easy to
       | type and easy to replace (rare in English). The project is called
       | "Jujutsu" because it matches "jj".
       | 
       | Yeah, it's just a coincidence that the world Jujutsu means magic
       | in japanese (Zhou Shu )
        
       | jayd16 wrote:
       | > Entire repo is under version control
       | 
       | I wonder how this works out for large files and cleaning them up.
        
         | martinvonz wrote:
         | I doesn't work very well yet. See
         | https://news.ycombinator.com/item?id=30399554.
        
       | qbasic_forever wrote:
       | That's very cool to have support for rsync/dropbox collaboration
       | of the repo files. I'm always sad that there isn't a maintained
       | p2p git implementation anymore. I'd love to just dump a bare repo
       | to a syncthing share and collaborate with a small group of people
       | accessing it.
        
         | CRConrad wrote:
         | > there isn't a maintained p2p git implementation anymore.
         | 
         | What, it isn't actually a decentralised distributed system any
         | more?!?
         | 
         | > I'd love to just dump a bare repo to a syncthing share and
         | collaborate with a small group of people accessing it.
         | 
         | Are you saying one can't do that with the latest versions of
         | git?
         | 
         | WTF, when did this happen and how can I have missed what must
         | have been huge news when it happened?
        
           | qbasic_forever wrote:
           | You can have sync conflicts with multiple people pushing to a
           | bare repo on a shared folder at the same time. This kind of
           | file sharing with git only works on NFS or filesystems that
           | support locking (look at the git manual for this warning).
           | Syncthing doesn't support that--it _might_ work for some
           | time, but stress it with multiple people all at once and it
           | will explode into sync conflicts eventually.
        
           | NateEag wrote:
           | As one who has set up skunkworks git boxes before, I think OP
           | is probably referring to the fact that there is not a no-
           | brainer out-of-the-box way for git repos on different dev
           | machines to autodiscover each other, even on a local network.
           | 
           | You can have everyone manually set up a git hosting env on
           | their dev machine, then have everyone manually add a remote
           | for every other developer's box, but it sure isn't
           | convenient.
           | 
           | And if you settle on sharing one central box as the canonical
           | node (which IMO is the right answer), you're no longer truly
           | using a distributed system - it's a de facto centralized
           | system.
        
             | qbasic_forever wrote:
             | Exactly, syncthing has flawless p2p discovery and
             | networking/sharing of files. Being able to put a git bare
             | repo effectively on a syncthing share would be super
             | convenient for small private collaboration. Tailscale might
             | be an option to make a bunch of local git repos all start
             | pushing/pulling, but it has some headaches too and isn't
             | really designed for opening up small single services.
        
       | danbmil99 wrote:
       | Does it support lfs, or deal with large binary assets in some
       | other way?
        
         | martinvonz wrote:
         | No, there's no particular support for large files yet.
        
       | ParetoOptimal wrote:
       | I've long wished Pijul had a git backend because I think it might
       | be superior but strongly feel the only way it could get mass
       | adoption even if it's truly better is if people could just try it
       | on their git repos like this.
       | 
       | Removing the "convince my team to move away from git" part of a
       | better DVCS could make jujutsu very popular.
       | 
       | Or other git compatible spinoffs could be made that follow this
       | approach and explore other design spaces.
        
       | jareds wrote:
       | This looks interesting and I'm glad to see that people are not
       | viewing SCM as a solved issue. While I don't think I'd use this
       | on professional projects yet I'm interested at looking at this
       | for personal projects since I can use the Git back-end and
       | continue to use Github to host my code. I feel like Git has
       | become such a DeFacto standard that nothing is going to replace
       | it any time soon. I've been programming for long enough to
       | remember feeling the same way about SVN though so I assume
       | something will eventually supplant Git.
        
         | freedomben wrote:
         | I remember that well too (along with Rational Clearcase), and
         | you may totally be right, but git does feel different because
         | it works so well with all sorts of projects, big and small.
         | There were always operations that required hacks. With git that
         | doesn't feel the case to me,perhaps with one exception (but I
         | don't think this is git's fault as much as it's mine for not
         | knowing git well enough to use the tools it provides): if I'm
         | working simultaneously on two different branches (for example
         | one branch is a bug fix that requires 20 minutes to build and
         | deploy before I can test it, so I work on other things while
         | it's running), I often have two different checkouts so I can
         | (mostly) avoid having to git stash.
         | 
         | That said though, you are probably right something will
         | eventually supplant git. It would be arrogant to think that my
         | failure to imagine something better means there isn't anything.
        
           | Hendrikto wrote:
           | What you are describing sounds as if you want worktrees:
           | https://git-scm.com/docs/git-worktree
        
             | freedomben wrote:
             | Whoa, thank you! That does look like the answer!
        
           | skissane wrote:
           | > There were always operations that required hacks. With git
           | that doesn't feel the case to me,perhaps with one exception
           | 
           | I think the way Git handles renames is ugly - it doesn't
           | actually record them, it just tries to guess when they occur
           | based on file contents (inevitably imperfect). I think
           | Subversion handled this better.
           | 
           | The problem is that a Git tree object only contains file
           | name, file mode, and blob/subtree hash. If it also contained
           | some kind of "file ID" (such as a UUID), then you could track
           | renames properly - renaming a file would change its name but
           | not its file ID, so you'd track the rename properly, even if
           | the contents changed at the same time.
           | 
           | Given they didn't do that... maybe create a file-id Git
           | attribute? (Alas, "git mv" doesn't update .gitattributes, so
           | renaming a file forgets the attributes; but it could learn.)
        
             | sdesol wrote:
             | I do agree that renaming/moving files isn't great but I
             | guess that is one of the downsides of having a distributed
             | version control system. With Subversion, ClearCase, and
             | others, they were centralized and very much meta-data
             | driven.
             | 
             | I'm not quite sure why Linus decided not to make
             | renames/moves/copies explicit/strict and my only guess is
             | it simplified things. Being able to say with 100% certainty
             | all the time that something was renamed or copied is
             | extremely handy, but with Git we just get a percentage like
             | the following shows:
             | 
             | https://oss.gitsense.com/insights/github?bq=move%2Bpull-
             | age%...
             | 
             | I guess knowing the mapper.go file in the example above was
             | likely copied is good to know, but it would be much better
             | to know this with 100% certainty.
             | 
             | Full disclosure: The link above goes to my tool
        
               | skissane wrote:
               | > I do agree that renaming/moving files isn't great but I
               | guess that is one of the downsides of having a
               | distributed version control system. With Subversion,
               | ClearCase, and others, they were centralized and very
               | much meta-data driven.
               | 
               | I don't think it has anything to do with the fact that
               | Git is distributed. It is a question of how rich the
               | repository data model is. The richness of the repository
               | data model is an orthogonal concern from distributed-vs-
               | centralised.
               | 
               | I think Linus just wanted to keep it as simple as
               | possible - but, maybe in some areas he made it too
               | simple. The Subversion developers on the contrary, maybe
               | went too far in the other direction.
        
               | sdesol wrote:
               | > I don't think it has anything to do with the fact that
               | Git is distributed.
               | 
               | I think it does since meta-data increases merge
               | complexity, which is probably a headache when dealing
               | with a distributed system. With a centralized system, you
               | are basically creating a lock when you do a
               | rename/copy/etc. which doesn't translate well to
               | distributed systems.
               | 
               | With Git as it is currently implemented, you only need to
               | worry about one state which is the tree. With meta-data,
               | the number of states that needs to be tracked can
               | increase significantly.
               | 
               | Having said all of that, I guess it probably wouldn't be
               | too hard to implement a layer on top of Git that ensures
               | every directory has something like a .git.meta file and
               | have hooks that ensures all renames,copies,etc. are
               | recorded in the meta-data file.
        
               | skissane wrote:
               | > I think it does since meta-data increases merge
               | complexity, which is probably a headache when dealing
               | with a distributed system.
               | 
               | I disagree. In Git, merging always happens locally,
               | between two local commits; there is nothing distributed
               | about merging itself.
               | 
               | > With a centralized system, you are basically creating a
               | lock when you do a rename/copy/etc. which doesn't
               | translate well to distributed systems.
               | 
               | I don't think that is really true. If I rename a file in
               | Subversion, that doesn't involve "creating a lock". I
               | rename the file locally (using "svn mv"), Subversion
               | locally remembers I have done it, but doesn't send
               | anything to the server. When I want to commit, it then
               | contacts the server and uploads the commit data,
               | including the rename tracking info. Now, that commit
               | operation takes a write lock on the branch - to prevent
               | any other commit for that branch being processed at the
               | same time - but it is the exact same write lock
               | regardless of whether renames are involved or not. If we
               | take Subversion as an example of a centralised version
               | control system with rename tracking, the rename tracking
               | and the locking are orthogonal. (When I say "locking"
               | here, I mean the internal locks within the Subversion
               | server, not the end-user-visible advisory locks you get
               | with the "svn lock" command-that advisory locking feature
               | is unrelated to the topic of rename tracking.)
               | 
               | Like Git, merging is essentially a local process in
               | Subversion - the client constructs a merge commit, and
               | then sends the completed merge commit to the server. The
               | actual merge, meaning construction of the merge commit
               | contents, always happens on the client side, at least as
               | far as the core Subversion protocol is concerned.
        
               | skissane wrote:
               | > Now, that commit operation takes a write lock on the
               | branch - to prevent any other commit for that branch
               | being processed at the same time
               | 
               | In fact on the whole repo, since branches are just
               | subdirectories. (Shows how long it has been since I've
               | actually used Subversion, I'm starting to forget it.)
        
           | jeltz wrote:
           | I totally agree. Back when I used Subversion it felt to me
           | like there obviously must be a better way to version control
           | and that the tool got in my way all the time. Git on the
           | other hand almost always can solve my problems and while some
           | things could be improved (confusing UX, a bit too complex,
           | plus bad handling of conflicts) it is much closer to the
           | right tool for VCS than Subversion ever was.
        
             | fsloth wrote:
             | What are the problems that Subversion has? My only
             | experience of svn is of simple personal projects and in
             | that scope it worked pretty well - not contesting your
             | opinion, but would like to know at which point svn becomes
             | problematic.
        
               | netghost wrote:
               | If subversion had branches, they were not nearly as easy
               | to use as in git. It also didn't have a great notion of
               | offline work (to my memory).
               | 
               | For what it's worth, SVN was pretty straightforward and
               | worked well enough at the time. Later, Mercurial
               | addressed SVN's deficiencies with a familiar interface.
        
               | jareds wrote:
               | IN my experience pull requests were not a thing in
               | Subversion. We would attach patch files to Jira for code
               | reviews. Git allowed for much easier workflow with
               | merging branches instead of directly applying patches to
               | trunk. This probably has a lot to do with the fact that
               | we used Bitbucket for Git hosting and a plain Subversion
               | server with no extra features to help with code reviews.
        
       | adamnemecek wrote:
       | Rust has truly reinvigorated these types of tools.
        
       | kyrra wrote:
       | For those that didn't look, this is 100% rust.
        
         | tonetheman wrote:
        
         | tuwtuwtuwtuw wrote:
         | Seems irrelevant to me. Why do you care about the language
         | choice?
        
           | throwaway81523 wrote:
           | Because this is hacker news, not user news.
        
           | usrusr wrote:
           | People do tend to see tools written in a systems language in
           | another light than tools written in a glue language. Did you
           | read it as "rust (not C)" or did you read it as "rust (not
           | Python)"?
        
             | tuwtuwtuwtuw wrote:
             | Neither of those. I just read it as "rust".
        
             | em-bee wrote:
             | i used to look down on languages other than C, considering
             | programs written in C a better choice than eg. python. i
             | have since reversed my stance because i realized that
             | python is a lot more hackable. i haven't tried rust yet,
             | but i would prefer it over C for sure. compared to python i
             | won't know until i actually get familiar with rust.
        
           | KerrAvon wrote:
           | On the negative side: In some environments it's a hurdle to
           | build programs in Rust.
           | 
           | On the positive side: It signifies a certain likelihood of
           | memory and data safety that you won't get in most other
           | languages.
        
           | binarypaean wrote:
           | Language matters quite a bit to those considering
           | contributing. It also provides some context for expectations
           | about performance and reliability thanks to language idioms,
           | features and culture.
        
             | detaro wrote:
             | But the info is right on the linked page. Somehow I don't
             | think people who haven't even followed the submission link
             | aren't the ones to worry about yet for "potential
             | contributor".
        
           | ccbccccbbcccbb wrote:
           | Because it's trendy to praise brushes instead of paintings,
           | vinyl pressing quality instead of music, and languages
           | instead of software these days.
           | 
           | Jean Baudrillard would call it another level of simulation.
        
         | martinvonz wrote:
         | Note, though, that it depends on libgit2 (which is written in
         | C). (As pointed out by someone in
         | https://github.com/martinvonz/jj/issues/56.)
        
       | AnonC wrote:
       | I'm curious to know if this has any similarities with fossil
       | (https://fossil-scm.org/ ). If it does, it would be nice to see
       | that in the documentation.
        
         | throwaway81523 wrote:
         | Fossil is ideologically different, it wants to preserve every
         | artifact, no rebasing allowed.
        
           | cryptonector wrote:
           | That Fossil doesn't support rebase is a fiction, since it
           | supports cherry-pick. All that's missing is a script around
           | cherry-pick, which is all rebase is.
        
       | BiteCode_dev wrote:
       | " It also means that you can always check out a different commit
       | without first explicitly committing the working copy changes (you
       | can even check out a different commit while resolving merge
       | conflicts)."
       | 
       | That's really interesting. Having to manage stashes is annoying.
        
         | halfdan wrote:
         | Try using git worktrees: https://geekmonkey.org/rethink-your-
         | git-workflow-with-git-wo...
        
           | BiteCode_dev wrote:
           | How do you use worktrees with an IDE ? Do you have one
           | project per tree ?
        
           | pjc50 wrote:
           | Surprise limitation: you cannot have two worktrees set to the
           | same branch, or at least that confronted me when I tried it.
        
             | halfdan wrote:
             | That's not correct. You can use --force to to create a
             | duplicate worktree pointing to the same commit-ish:
             | https://git-scm.com/docs/git-worktree#Documentation/git-
             | work...
        
             | [deleted]
        
             | jomar wrote:
             | If you had two worktrees set to the same branch and made a
             | new commit in one of them (thus changing the commit the
             | branch ref points to), what would happen in the other
             | worktree?
             | 
             | Either it wouldn't have the right commit checked out
             | anymore, or git would have to miraculously change what
             | files are checked out in it -- which would likely come as a
             | big surprise to whatever you were doing in that working
             | tree.
             | 
             | Ergo, it is forbidden.
             | 
             | I periodically find myself creating a new (temporary)
             | branch referring to the same commit when I want a new
             | worktree looking at the same place, or just create a new
             | worktree with a detached HEAD looking at the same commit.
        
               | Too wrote:
               | Git could hide this for you and just make it look like
               | you cloned the repo twice.
               | 
               | What happens if you make a commit in dir1 and dir2 is on
               | the same branch. Absolutely nothing, until you fetch, and
               | worktrees could work the same way. If there is any
               | ambiguity left you could prefix the branch names similar
               | to the remotes origin/master, worktree2/master.
               | 
               | The only sane way to use worktrees today is, like you
               | say, with detached heads. Which well...isn't that sane
               | for many other reasons.
        
               | jomar wrote:
               | If you want a separate clone you know where to find it,
               | but then you will be plagued by the uncertainty I
               | mentioned in my other comment
               | (https://news.ycombinator.com/item?id=30400869).
               | 
               | I did not say that was the only sane way to use
               | worktrees. I frequently use them for separate strands of
               | ongoing work (on separate branches per work strand, named
               | appropriately). Less common (for me) is the use case of
               | easy reference to older versions, with more ephemeral
               | worktrees checking out a tag, a new branch (created for
               | the purpose, and short-lived), or a particular commit
               | (viewed as a detached HEAD).
        
               | emn13 wrote:
               | git could simply prevent you from committing to that
               | branch in that case, and perhaps print a warning when
               | adding a worktree. The current behavior is weird. Another
               | alternative is to allow the commit, but leave it in a
               | detached-head state, and let the user choose how to fix
               | that retrospectively.
               | 
               | The way I use worktrees I'd say the majority are read-
               | only anyhow, so abiding by restrictions because it
               | _might_ get confusing if a commit were made is pretty
               | annoying.
        
             | hpfr wrote:
             | Can you elaborate on why you would want two worktrees set
             | to the same branch? I think if I were trying to compare two
             | approaches involving incompatible changes, creating a
             | branch for one approach would feel more natural anyway, and
             | then I'd be able to use the worktrees.
        
           | CorrectHorseBat wrote:
           | What is the advantage of using worktrees over another
           | checkout in another folder?
        
             | 0xdky wrote:
             | You will need a full repository in other directory to
             | checkout and this will waste storage unless you share
             | objects via alternate.
        
             | jomar wrote:
             | When you're done with a worktree, you just delete it (via
             | `git worktree remove`). Any additional branches or stashes
             | etc are part of the repository that the worktree was part
             | of, and they (of course) remain.
             | 
             | When you're done working in a separately cloned repository
             | in another folder, if you're anything like me, before
             | deleting it (via `rm -rf`) you'll want to check very
             | carefully for additional branches, unpushed work, anything
             | stashed. Deleting an entire repository that's been around
             | for a while is a risky operation in that it may have
             | accumulated other unrelated work in addition to the current
             | branch (which was the primary reason for the clone), and
             | you'll want to check carefully before deleting the whole
             | lot.
             | 
             | Additional worktrees within the same repository are great
             | for medium-term ephemeral separate strands of work. They
             | can be created and removed without concern.
        
             | ossusermivami wrote:
             | Optimizations and management really
        
             | halfdan wrote:
             | Duplicate storage as already mentioned, but you will also
             | lose the ability to merge / doff cross branches if you have
             | separate checkouts.
        
               | cortesoft wrote:
               | Why would you lose that ability? You can just pull from
               | the other checkout as an upstream, right?
        
               | jonathanlydall wrote:
               | Worktree allows you to checkout other branches, stashes
               | or commits which are local only / not yet pushed.
               | 
               | What's also great is that you don't need to do a pull in
               | the other folder. Before I discovered worktree, I had my
               | repository checked out in two places, so was either
               | pulling both constantly, or when I needed the alternate,
               | it was often very far behind and I had to pull a lot.
        
               | CorrectHorseBat wrote:
               | Hmm, I tried it once and iirc I couldn't see
               | commits/branches of the other workspace without pushing
               | and fetching so I really didn't see any difference. With
               | different checkouts you can also easily do that by adding
               | the other checkout as a remote.
        
               | dataflow wrote:
               | Something probably got messed up on your setup (or maybe
               | you checked out a commit instead of a branch?) because
               | you definitely can see all worktrees' branches from
               | inside each other when using git worktree.
        
               | CorrectHorseBat wrote:
               | That makes sense. Now I think about it, The issue
               | probably was that I was working in a submodule and those
               | branches are probably not shared.
        
               | jonathanlydall wrote:
               | Yes, as per my other comment, I've noticed with
               | submodules that the references are isolated between the
               | different folders, but they do share the same objects in
               | the .git folder, so you still get efficiency there in not
               | needing to store or pull duplicate data.
        
               | jonathanlydall wrote:
               | Not sure what you were doing wrong, but I use worktree
               | regularly and you can absolutely see the same commits
               | from both the primary and worktree side.
               | 
               | The great thing about worktrees is that everything local
               | is still available in the worktree and vice-versa, you
               | can even stash push on the one side and pop on the other.
               | You also don't need to push or pull on either side first.
               | 
               | I have noticed that for submodules, although they share
               | the .git folder, they don't share references, so you
               | can't see local branches and stashes between the
               | worktrees, but sub module pulls are still quicker since
               | they share objects so those don't need re-pulled on the
               | other folder.
        
         | floatboth wrote:
         | rebase.autostash=true is also a thing, but the "working copy as
         | commit" concept does look more interesting.
        
       | daniel-cussen wrote:
       | I hope this popularizes the correct spelling of Jujutsu.
        
       | blagie wrote:
       | This seems really nice.
       | 
       | git got the data model really right, and the user space really
       | wrong. The data model is more important than the user space.
       | 
       | This is the first project I've seen which appears to understand
       | and respect /how/ and /why/ the git data model is so elegant.
        
         | dane-pgp wrote:
         | > The data model is more important than the user space.
         | 
         | For those interested in the different perspectives on how to
         | weigh those priorities, I recommend starting here:
         | 
         | https://en.wikipedia.org/wiki/Worse_is_better
        
           | somebodythere wrote:
           | I think the programmer tendency to think of usability as an
           | implementation detail is probably why open-source app UX was
           | considered a joke for so many years. Only now is that
           | perception starting to change, because enough people have
           | taken an interest in the space who make usability a priority.
        
             | antifa wrote:
             | More like, people who've taken an interest in the space are
             | having a much harder time finding jobs that aren't "fill
             | this electron app/SaaS with dark patterns."
        
         | carlhjerpe wrote:
         | The pijul model makes even more sense to my brain, being patch
         | based solves a lot of branching issues.
        
           | blagie wrote:
           | One of the many breakthroughs in git was precisely not being
           | patch based. Being patch-based means that the tools for
           | comparing versions are hard-coded into the data format. One
           | of the major upsides of CVS->SVN, for example, was support
           | for file moves. Simple issues like this weren't possible to
           | fix without reworking the whole system.
           | 
           | With a version-based model, how you compare them is
           | determined by the user space, whether that's merges, or
           | viewing history. Even compression isn't all that fundamental
           | to much of anything; it's possible to implement underneath
           | the system, eliminating whatever redundancy you want. With
           | patch-based systems, all of that comes baked into the
           | underlying representation.
           | 
           | On a deeper level, this feeds into how git can be
           | distributed, robust, yet very simple.
        
             | carlhjerpe wrote:
             | It also means cherry picking commits between branches
             | prevents clean merging afterwards meaning you have to force
             | yourself to keep branches short-lived. The patch graph
             | pijul gives you doesn't have this issue. I'm not an expert,
             | but when reading the Pijul blog it made a lot of sense for
             | me.
        
       | lostintangent wrote:
       | This is awesome! And it's so exciting to see folks investing
       | energy into this problem space.
       | 
       | Out of curiosity: did you add support for multiple backends
       | because you don't think Git will ultimately be sufficient for the
       | experience you want to create? Or did you just want to ensure
       | that the tool didn't become unnecessarily coupled to Git?
        
         | martinvonz wrote:
         | Good question. You're right on both guesses. One reason is that
         | I want to make sure the API works well enough that it's easy to
         | replace the backend. The current native backend is called
         | `local_store` because it stores files locally (just like the
         | Git backend does). I want to be able to add another backend
         | that fetches objects from a remote instead (and caches them
         | locally), although another option is to hide that part inside
         | the backend like Git does with its partial clone support. I
         | also want to be able to add more functionality that the Git
         | backend doesn't have. Maybe that would be tracking of renames,
         | or maybe something I haven't though of yet.
        
           | ParetoOptimal wrote:
           | > I also want to be able to add more functionality that the
           | Git backend doesn't have. Maybe that would be tracking of
           | renames, or maybe something I haven't though of yet.
           | 
           | Awesome, that would enable a realistic no-risk path to
           | adoption for most projects:
           | 
           | - trying jujutsu on work codebase
           | 
           | - if useful, tell a coworker and maybe they try it
           | 
           | - present internally about pros
           | 
           | - team tries and agrees its better, adopts it
           | 
           | - after some months confidence is built, give a presentation
           | on features you could get with jujutsu native backend, gauge
           | interests\worth
        
       | uses wrote:
       | Maybe I'm too brainwashed by git, but it seems to me one of its
       | benefits is the way the index works. You're encouraged to be
       | fairly explicit about what you're adding to a commit, which
       | encourages making a nice version history. Why would I want
       | everything I do to automatically be added to a commit by default?
       | Doesn't this encourage me to either put all kinds of unintended,
       | not-ready crap in my commits, or constantly manage the equivalent
       | of .gitignore? What am I misunderstanding about the benefits of
       | how this works?
        
         | ezst wrote:
         | > Maybe I'm too brainwashed by git, but it seems to me one of
         | its benefits is the way the index works.
         | 
         | And maybe I'm too brainwashed by Mercurial, but to me the index
         | is nothing but a single weird commit with only downsides (why
         | do we need a UI to work with the index that's different from
         | the one to interact with commits, although the capabilities
         | should be the same? Why being limited to a single index and not
         | several? Why the different versioning/shareability
         | characteristics, etc).
         | 
         | I largely prefer Mercurial's "public vs draft" strategy and the
         | "commit what you have and we give you the tools to tidy up the
         | series whenever you feel like it". In practice it means that
         | you have as many "indexes" as your series is long, and with
         | hg's mutable-history and amazing history-rewriting extensions
         | like absorb, it's much more convenient, fast and safe to work
         | with than the git inconsistent equivalents.
        
         | shp0ngle wrote:
         | Exactly. Reading the docs makes me feel something is a bit
         | "wrong".
         | 
         | But I felt like this before when I switched from subversion to
         | git ("why would I download all history, always???") so, who
         | knows.
        
         | markstos wrote:
         | You are too brainwashed by git.:)
         | 
         | The bigger picture is that the project is trying to provide a
         | better interface on top of the existing git data store. As
         | someone who used darcs for a major project before Git dominated
         | DVCS, there are much better user interfaces than what Git
         | offers, and attempts to improve upon Git is a diversity to
         | encourage.
         | 
         | Unlike picking your own text editor, a whole team has to agree
         | about the choice of DVCS, making it harder to try new ones.
         | 
         | The beauty of a solution with a Git-compatible data store is it
         | allows some people on the team to experiment with it while
         | still collaborating with people using Git.
        
         | krick wrote:
         | Your phrasing makes me think if I'm just too brainwashed by git
         | as well, but, yeah, I wouldn't want anything to be added by
         | default at all. While working I do all kinds of stuff I'm not
         | going to commit, like debug statements and rough sketches,
         | maybe some temporary scripts. And even though I do usually
         | glance over diffs in the end, I don't really read them: that
         | is, even if I did, it's not really my thoughts I see on the
         | screen at that point, I'm as likely to notice mistakes there as
         | I am in somebody else's code, if not less.
         | 
         | When I'm _adding_ a change, on the contrary, it 's something I
         | wrote minutes to seconds ago, I _know_ what 's in that code,
         | and by adding that I'm kind of making a statement that this
         | wasn't some random bullshit I do with the code, but something I
         | intend to keep (even if later I'll completely change that while
         | interactively rebasing or something like that).
         | 
         | On the other hand, I didn't complain that much back in the day
         | when I was using SVN. But I feel like my current workflow that
         | employs most unique features of git is actually much better.
         | Basically, horribly inconsistent CLI is the only complaint I
         | have about git.
        
           | JuettnerDistrib wrote:
           | > I wouldn't want anything to be added by default
           | 
           | This line of reasoning works really well for those who
           | understand (and want to understand) how git works. I know
           | plenty of people who don't care about their development tools
           | (e.g. scientists), and for them the index is a chore in the
           | way of more important problems.
        
         | gitgud wrote:
         | Does that mean that there's no "staged changes" in Jujutsu?
         | That's one of my favourite and ironically hated parts of git...
        
           | martinvonz wrote:
           | Yes, no staging area. Does
           | https://github.com/martinvonz/jj/blob/main/docs/git-
           | comparis... help address your concern?
        
         | TillE wrote:
         | There are already popular Git GUIs like GitHub Desktop which
         | abstract away the staging area. It's also how basically every
         | other VCS works.
         | 
         | Yeah, you should have an appropriately comprehensive .gitignore
         | file, that's good practice in any case.
        
         | jeltz wrote:
         | Agreed, the index is one of my favorite parts of git. I do
         | _not_ want to add everything almost ever.
        
       ___________________________________________________________________
       (page generated 2022-02-20 23:01 UTC)