8 ms·
I'm becoming less enamored with git over time. I've used it for years (by choice, and I'm a GitHub user), but have never been a power user. I'm annoyed at how
by haberman 16y ago
I'm becoming less enamored with git over time. I've used it for years (by choice, and I'm a GitHub user), but have never been a power user.
I'm annoyed at how the very most basic workflows in Git seem awkward, like I'm working against the tool instead of with it. The simplest example is: I have a hacked-up tree, but I know changes have been made upstream, and I want to pull those changes:
$ git pull
Updating 73f91c3..0ee9fa8
error: Entry 'README' not uptodate. Cannot merge.
It's complaining because I've modified README locally, which was also modified remotely. Every other reasonable version control system I've ever used will happily merge the upstream changes with my not-yet-committed local changes. But Git refuses. This is annoying.
What I have to do now is commit my hacked-up, non-compiling, possibly-swear-word-containing in-progress changes. I really dislike this. To me, "commit" means "take a finished bit of work and add it to the global history." I really dislike having to commit something that is extremely unfinished just because I wanted to integrate some upstream changes.
So what I usually do in this situation is "git stash", "git pull", "git stash apply." This works ok for the "pull" case. But what if I have multiple sets of locally-hacked-up changes? Like suppose I was working on one change when I realized that there's something else I should really fix first. "git stash" quickly becomes limiting, since you can't name the individual changes, so you get this list of changes that you don't know what they are or what branch/commit they were based on. In other VCS's like Perforce, you can have multiple sets of independent changes in your working tree. Not possible with Git AFAIK.
Anyway, I'll probably keep using Git, but I'm not as enamored with it as I once was. I used to figure this was all just porcelain issues that would be refined over time, but it doesn't seem to be getting any better.
- mseebach 16y agoIt seems that what you're really hitting is the, erhm, ill-advised decision to name most of git's most common actions the same as actions in subversion, but make them do significantly different things. Git's "commit" should probably have been named "mark" or whatever because "push" is what's actually comparable to a subversion commit. I've mostly conditioned myself by now, but I also recall some fun with checkout.
- haberman 16y agoWhether it's called "commit" or "mark", I have to write a commit message, which I don't want to do unless my tree has reached a state where I have actually accomplished something. The commit becomes part of the history, which will be visible upstream unless I squash later, and I definitely don't want upstream to see a series of commits where my tree is completely broken.
- burgerbrain 16y agoThe problem here seems to be that you're working against git, not with it. Committing and branching should be things that you do casually in git, by making a big deal out of them you're limiting yourself and crippling git. If you try to use a screwdriver like you use a hammer, you're always going to be disappointed.
- waqf 16y agoPersonally I write crappy commit messages for all those commits I'm going to squash before publishing. git is guilty, but only of giving you too much rope and not enough direction.
- xentronium 16y ago> It's complaining because I've modified README locally, which was also modified remotely. Every other reasonable version control system I've ever used will happily merge the upstream changes with my not-yet-committed local changes. But Git refuses. This is annoying. No it isn't. Git is trying to be predictable. > Like suppose I was working on one change when I realized that there's something else I should really fix first. Branches are designed to resolve this problem. When you want to do something that takes a lot of time, you branch from the stable version. When you need to do something else, you branch from the stable version again.
- haberman 16y agoYou are completely ignoring my objection that I don't want to "commit" a tree that is totally broken. What should my commit message be? "Tree is totally broken and doesn't compile, but Git made me do this to pull upstream changes." There is nothing logical/reasonable for me to write in that commit message. I definitely don't want that commit to make it upstream. Sure, I could squash later, but why is Git forcing me to do something that doesn't have any value (write a "commit" message for a tree that is totally broken)?
- branden 16y agoStash, pull, stash pop. Arguably not the most intuitive solution, but there ya go.
- haberman 16y agoAlso, I say that something is annoying to me, and you say "No it isn't." How can you deny that something is annoying to me? Ignoring what a user actually wants because it's not what you think they should want is the classic hacker UI design failing.
- weaksauce 16y agoCan you not do a stash --patch multiple times and give each patch a unique message? That would solve the many unrelated hacks problem I would think.
- js2 16y agoIt's complaining because I've modified README locally, which was also modified remotely. Every other reasonable version control system I've ever used will happily merge the upstream changes with my not-yet-committed local changes. But Git refuses. This is annoying. Commit-before-merge is not a limitation, it is a feature of DVCS's. Merge-before-commit is broken by design, as you are modifying your unsaved work, and there is no way to get back to your pre-merge state (say you decide the merge conflicts are too much to deal with at the moment). So you are correct, git will not let you merge if youmhave uncomitted work that would be affected by the merge, but it's really just trying to keep you from losing work, not trying to annoy you. That said, this is one of the use cases for 'git stash' which will set aside your uncommitted work. You can then do the 'git pull' and then unstash (stash pop) your work. The advantage of this is that you can always undo the merge if you decide it's not what you wanted afterall. With merge-before-commit, you'd have no such option unless you manually set aside your work. But what if I have multiple sets of locally-hacked-up changes? Like suppose I was working on one change when I realized that there's something else I should really fix first. "git stash" quickly becomes limiting, since you can't name the individual changes, so you get this list of changes that you don't know what they are or what branch/commit they were based on. In other VCS's like Perforce, you can have multiple sets of independent changes in your working tree. Not possible with Git AFAIK. This is what branches are for. Do not be afraid to commit work in progress... you can always polish up that work before you share those changes. For example: git checkout -b feature origin/master edit, ut oh, interuption, git commit -a -m WIP git checkout -b bugfix-1234 origin/master fix bug, git commit -m "fixed bug" git push origin HEAD:master git checkout feature git reset HEAD^ # removes the WIP commit, but leaves its changes in your working copy. I hope that gives you a better idea of how you can use branches. You might also want to spend some time reading up on rebase -i. Basically, start thinking of your localc branches as independent patch queues that you can freely edit, reorder, etc until they are ready to be shared. At which point you can push them out to the world. HTH.
- haberman 16y ago> it's really just trying to keep you from losing work, not trying to annoy you. The same thing could be achieved by having Git automatically create an "undo" commit before performing the merge. Then you could revert to pre-merge state with "git pull --undo", just like you can abort a rebase with "git rebase --abort." Optimize for the common case. Of probably hundreds of merge-before-commit operations I have performed with other VCS's, I can't think of a single time I have wanted to undo this operation (after all, if upstream has changed you're going to have to merge sooner or later -- it might as well be now). On the other hand, I am annoyed by commit-before-merge every single time I perform a pull. > This is what branches are for. Do not be afraid to commit work in progress... I'll have to try the "git reset" approach, I hadn't thought of that before. But even that has issues IMO: 1. "git reset" is a data-losing operation if you call it with certain parameters. For example, "git reset --hard HEAD^" would throw away the WIP! I'm wary of making such a command something I type all the time, because there's always the risk that I'll call it wrong. 2. I have to do this dance of "commit, checkout, pull, checkout, rebase" just to pull upstream changes. And when I want to actually push the change upstream, I have to "merge --squash" and then delete the old branch (otherwise lots of branches will build up and I won't know which ones have been committed and which haven't). It's a lot of annoying overhead. I'd rather just work on master where I can just "pull", and branch only if I really want to work on two big changes in parallel. > HTH. I really do appreciate that you were genuinely trying to be helpful (as opposed to other replies). But my frustration remains that Git doesn't let me work the way I want to, and makes me perform contortions to fit its way of working.
- wnoise 16y agoDon't pull. Pull is two operations -- fetching the upstream work, and merging it in to your current branch. It's true that CVS and SVN both let you do this with dirty trees, but it's generally not what you should really be doing. Merges are hard and every update from "upstream" merged into your local changes has a chance of breaking your local changes. "git fetch" and "git remote update" both let you do the fetch without the merge. Once you have the updates, you can then decide what to do with them, which may have lots more options than just a simple implicit merge that most tools provide: rebase, overwrite, ignore for now and handle later when your work is in a cleaner state, etc. Git has tools to manage this in the case of long running lines of development. Providing them for uncommitted changes is a much harder task (precisely because you can't name your work and roll back to it), and mostly unnecessary because commits are so lightweight. This is your fundamental issue with git -- commits still feel heavyweight to you. Git's model really is fundamentally not "get everybody's local changes working with the exact same upstream code" (indeed for the upstream author, they may trust their code far more than the code they are pulling). Instead it is closer to "let everybody pick what changes and history to use in order to create their own coherent source". DVCS means each developer chooses what history to treat as authoritative. As such, temporary commits, temporary branches, and rewriting unshared history are encouraged.
- deleted 16y ago[deleted]