7 ms·
Fix conflicts only once with Git rerere
- lukasm 12y agoI'm now suffering a lot of rebase pain while working on a new .Net project. I'll give it a go. I'd be great if there was a strategy for fixing conflicts with VS files.
- eterm 12y agoThe inability of VS to play nicely with merging is a real pain. (DBML files in particular are a huge headache, but .csproj, .sln, .config files also are troublematic). I'm not sure I follow the author's issue with control merges though. Apart from a dogmatic statement that merges should be final (says who), what problems do control merges create?
- stinos 12y agoWhat problems did you have exactly with sln/project/config files? They are plain text after all so if there are conflicts they should be of the same 'level' as conflicts in code files (i.e. can be a breeze to merge or a f*ing pain depending on the situation).
- DougWebb 12y agoThe problems are twofold. First, these files and some others that VS uses are XML, and XML has this property where semantically-equivalent files can be structurally-different. Empty elements can be rendered with or without end tags, empty attributes can be present or absent, whitespace between tags doesn't matter, etc. (sln files aren't really XML, but they're XML-like in their structure. I've had fewer problems with them than the other files.) The second issue is the way Visual Studio modifies these files: it reads and parses them into a DOM tree, makes changes to the DOM, and then serializes the DOM back out to the file. So a small change in one part of the project causes the entire file to be re-written, and it often gets restructured in the process. I've found this to be a bigger problem when different developers are using different versions of Visual Studio; at my company we've had 2010, 2012, and 2013 all in use at the same time on the same projects until everyone upgraded. (And we had good reasons for not upgrading everyone at once.) I guess there's a third reason: most .NET developers never look at these files directly; for the most part they are only modified through Visual Studio. So, although they're just text files and conflicts are resolved the same way they're resolved in code, that's made more difficult by not knowing what the files are supposed to look like or what the correct resolution should be. The sln files are particularly annoying in this regard because they're about 80% Guid strings and 20% readable text, so it can be really hard to understand the diff. When I started working with .NET, I had to learn all about these file formats when I started running into conflicts in them, and now I'm comfortable fixing conflicts and often editing them directly. I've helped most of my team gain the same comfort level, so we don't have problems anymore. The conflicts, when they happen, are just annoying now.
- ljoshua 12y agoI'll second this. Half of my conflicts when working on .NET projects are related to changes in .csproj, DBML, or EDMX files. I understand the function these files perform, but it certainly doesn't make it any easier. Just because I and a colleague happened to both add completely independent files to a project doesn't mean I should have to deal with a conflict.
- lmm 12y agoI tend to find it best to .gitignore any IDE files. IDE project import can (or should be able to) regenerate them as and when necessary.
- mirlord 12y agoConflict re-resolution was literally the only thing that hurted me while using git. So now this tool is absolutely perfect for me.
- IanCal 12y agoFirst off, thanks for building and releasing something. I think I might be missing something though, I have never understood why having a clean history (when the real history isn't clean) is important. If you've got huge branches with scary merges, isn't the problem that you have huge long lived branches? Why does it matter that my graph shows when I actually did merge things? I usually hear a git bisect argument around this, but are there good examples where it becomes a problem? Bisect lets you specify when to skip a commit, so you can be as selective as you want with it. Lots of people complain about problems rebasing, and I've repeatedly seen issues where people mess up and that causes more pain when just merging seems to work perfectly fine. It seems like a lot of work, effort and time to avoid potential issues later (and even then I'm not sure what those issues are). This isn't rhetorical, given so many people have strong opinions on this I assume I'm missing something important.
- rlpb 12y agoIt's much easier to review a feature branch that has a clean history. Especially if it's remotely complex. If every commit is self-contained and each adds only one logical feature dependency, then every commit can be reviewed individually for correctness and unintended side-effects, rather than the entire complex diff as a whole.
- lumpypua 12y agoIf you really care about this, rebasing is a shitty solution. Patch queues like mercurial's make it much easier to logically decompose a feature into a series of patches and shuffle code between the commits until they all settle nicely. I say this having gone from a mercurial user that produced pristine commit histories to a git user that makes dirty, nasty histories.
- bronson 12y agoWhy are you making dirty, nasty histories? The git users on kernel.org sure don't, and I bet they have more complex branches in flight than you do...?
- 12y ago
- barrkel 12y agoThis is ugly and pollutes your history graph across branches. After all, a merge should only occur to merge a finalized branch in. This sounds like a completely arbitrary rule to me. I just don't get why people try so hard to avoid merges, and instead go down the rebase route. Rebasing isn't just a pain, it's rewriting history. It's potentially dangerous in a team environment. You can't distribute your rebased branch without a force push, and that risks two versions of the branch's commits getting into the repository, or losing someone's commits altogether. It's usually not worth the effort. It also presumes a simplistic development environment. Typically, I see branches that fit into categories; let's name them master, develop, small-feature, big-feature, next-gen-architecture. Small-feature branches can be rebased fairly easily. There's not many commits, they're most likely worked on by a single person so the history isn't distributed, and replaying the commits isn't too onerous. Big-feature branches are a little more tedious. This is where rebasing starts to become a pain; the big feature may have touched code that has since changed from commits of a few small-feature branches. Next-gen-architecture is where it all falls apart. Trying to do a major refactor while simultaneously keeping customers happy with smaller features is a fact of startup business, if not most businesses. Rebasing becomes a multi-hour exercise because there are hundreds, if not thousands of commits to replay. And everyone on the team has this branch, and there may be sub-branches of it that are destined to be merged into it. All the sub-branches need to be rebased too.
- dankohn1 12y agoWe've had good success encouraging daily merges of master into feature branches, and then using `git merge --squash` to avoid hopeless polluting of your history graph. Git merge squash essentially takes a diff of your feature branch and master and applies the diff as a single commit. See http://stackoverflow.com/a/25387972/1935918 http://stackoverflow.com/a/25387972/1935918 You lose the history of the feature branch, but we don't want that history anyway, since once tests are passing and the branch has been reviewed, we treat it as an atomic unit. That is, we might revert the whole commit, but we're not interested in reverting part of the commit.
- rtpg 12y agoDoesn't this make commits too big? On the team I'm working with right now, most people are making really small commits, but it makes git's history mechanism really useful. A single line change can be linked to a relatively small commit, it's extremely useful to figuring out the "why" of something. Having one commit for an entire feature would make that utility completely disappear
- Kiro 12y ago> This is ugly and pollutes your history graph across branches. After all, a merge should only occur to merge a finalized branch in. I thought it was best practice to merge master into your branch now and then to keep it up to date and avoid one big messy merge at the end. What is the disadvantage exactly?
- bronson 12y agoHe addresses this in the article: you then have multiple content-free merge commits in your history, making it more difficult to see where the branch actually begins (see "control merges polluting your history graph" in the artcle). Personally I don't think it's a big deal, but I understand if others take it seriously.
- Kiro 12y agoThanks. I read it but didn't see the big deal but putting it like that I can see why it would be. I still prefer doing it this way though.
- gitaarik 12y agoI think this is a great tool. I don't understand what other commenters are complaining about rebase and rewriting history, because this article is not about that, it's about not having to fix conflicts multiple times. This can be handy in a variety of situations. You might not need it, but every person/team has it's own way of working with Git. Rerere is just another tool that might help you in your workflow. And to the people who are claiming that rebasing is hard, dangerous or a clean history is not necessary: Once you get it's not hard or dangerous, and a clean history really IS useful. Why are we using Git again? - Being able to work together on a codebase (the history shows the changes) - Code reviews for new features (the history of the pull request shows the changes the feature introduces) - Being able to roll back to a previous state in case there is something wrong with the latest version (the history can help you decide where to roll back to) And a lot of more reasons we use Git that have to do with the history. It is true it takes a little bit more effort to have a clean history, but in big teams/projects it's really worth it.
- thewarrior 12y agoI agree with you for the most part but most of you would be better off if you keep this in mind : Don't rebase commits you have already pushed.
- sytse 12y agoExactly, if you have pushed it other developers might have referenced, merged or cherry-picked your code. Even if you marked it as a work in progress. And to roll back to a previous state it is not needed to rebase and/or have a linear history. Also see my article about this https://about.gitlab.com/2014/09/29/gitlab-flow/ https://about.gitlab.com/2014/09/29/gitlab-flow/
- gitaarik 12y agoA good usecase for pushing rebased work is at the end of a feature branch. For example, you've been working on a feature branch with a team for a time and now the feature is done and the branch can be merged back into master. However, the history of the feature branch might have been polluted with merge commits. To prevent merging these merge commits back into master, you can rebase the total feature branch on to master. It should be clear to the team that at this point, nobody is to work on that branch anymore and go back to master, or create a new branch (from master).
- foolinaround 12y agoFinally, an article that explains it comprehensively. My prior knowledge of it was hazy at best, and it seems like I did not take full advantage of this.
- ColinDabritz 12y agoNeat, I love how git has these tools that are so clearly targeted at 'I did this before' developer problems. Hey, I keep having to repeat this exact same merge, let's automate that. A similar problem is 'When did this break?', where you do the whole bit with "well it was working before here, but not now, it must have changed somewhere in the middle" then you're doing the binary search of the changesets between etc. The solution is called "bisecting a problem" as in cutting in half repeatedly. The git command/tool for this is: http://git-scm.com/docs/git-bisect http://git-scm.com/docs/git-bisect Using these commands, the system checks out versions in a binary search pattern, and asks you if this code is broken or not, then after some iterations tells you which commit broke things. Really handy. I suspect with some scripting if you could create an automated test you could wire it up to be completely automated as well.
- rqebmm 12y ago`git log --follow $NAME_OF_FILE` will show you each commit that contains a change for the given file. It's very handy when doing the "when did this break?" dance if you've narrowed down the potential files!
- gfunk911 12y agoThis post clicked for me. I tried and failed to use it once before, read this today and it worked immediately. Thanks!