Git/Atlassian Stash - how do combine commits before making a PR?



  • Yesterday my boss griped that my PRs have too many commits in them. I explained that this was due to:

    1. None of the Git clients I'm using supporting the "stash" command (meaning, I have to make a junk commit just to switch branches, since any given day I'm juggling 2-4 different branches)

    2. The need to check-in code at the end of each day so it'll be secure if my laptop gets run over by a bus (meaning, there's a lot of "work in progress" commits due to this)

    He accepted the explanation, but I also get his point that the "noisy" commits make it far harder to follow the history of the development branch in the repo.

    So! I turn to the "Git experts": how the hell do you combine commits on a remote branch? So far I've determined you can do it on a local branch by using an obscure feature of SourceTree which can be used to "replay" the commit history, which may help with case 1) above but is useless for case 2).

    Our workplace uses Atlassian Stash, if that helps... if it has a feature for this, I sure can't find it. Ditto SourceTree, which I have installed and configured-- if it has a feature for this, I sure as heck can't find it.



  • Here's a mockup of what I need:

    I support there's approximately zero chance that any useful GUI for this feature would come from anybody who thinks using Git is a good idea?



  • $ git rebase -i origin/your-remote-branch
    


  • @blakeyrat said:

    how the hell do you combine commits on a remote branch

    You can, maybe... but you shouldn't. Rewriting remote history can be really, really bad. I'm sorry if this isn't helpful, but combining remote commits could seriously ruin someone else's day.

    The better practice is to "squash" (Definition: turning multiple commits into one) all the local commits before you push them, if you can.

    As an alternate solution, maybe you could get a remote branch for your personal use that's just scratch space? Then you could cherry-pick and squash all the commits for a given task onto the local version of the legitimate target branch before pushing.

    Filed Under: Gibberish



  • Ok; I should have specified that I need answers that aren't useless gibberish. What does that do/how do I use it/what does it mean?



  • Look, it's this magical thing... the Internet!



  • @IngenieurLogiciel said:

    You can, maybe... but you shouldn't.

    Ok well I think I should. So does my boss. Thus this thread.

    @IngenieurLogiciel said:

    Rewriting remote history can be really, really bad.

    Because...?

    @IngenieurLogiciel said:

    I'm sorry if this isn't helpful, but combining remote commits could seriously ruin someone else's day.

    Who's? Why? How?

    @IngenieurLogiciel said:

    The better practice is to "squash" (Definition: turning multiple commits into one) all the local commits before you push them, if you can.

    Right; that's what my boss does. But then I asked him, "how do you do check-ins because you have to haul the laptop somewhere?" and he says, "well I don't", and then I said, "what if you drop your bag and your laptop gets run over by a truck?" and he had no answer to that.

    Do you?

    @IngenieurLogiciel said:

    As an alternate solution, maybe you could get a remote branch for your personal use that's just scratch space?

    Atlassian Stash doesn't allow that; every commit has to be attached to a Jira ticket. Even if it did, it doesn't solve the problem because:

    @IngenieurLogiciel said:

    Then you could cherry-pick and squash all the commits for a given task onto the local version of the legitimate target branch before pushing.

    I have no idea what that means or how to do it.

    @IngenieurLogiciel said:

    Filed Under: Gibberish

    Not as bad as Eldelshell's gibberish answer.



  • @Eldelshell said:

    Look, it's this magical thing... the Internet!

    The words "before pushing" are in the goddamned title of the page. Look, if you don't have an answer, please stop posting here. Coding Help is supposed to be a genuine support category, not a "hur hur hur let's piss off Blakeyrat" category.


  • Grade A Premium Asshole

    @blakeyrat said:

    Coding Help is supposed to be a genuine support category

    Part of that is assumed that those asking for help will not be a dick to those attempting to help them.



  • @Eldelshell said:

    git rebase -i origin/your-remote-branch

    It means you are interactively "rebasing" (restructuring commits - squashing them together, dropping them completely, even editing them and their messages - into a new set of commits with new hashes) the remote branch. Anyone who has the old commits you already pushed or has merged them in different branches could have problems (e.g. merge conflicts, or the commits could continue to exist in other remote branches or other user's local branches). Hopefully this answered some of your questions above and was less gibberish.



  • @blakeyrat said:

    Not as bad as Eldelshell's gibberish answer.

    You asked a question and I answered in the same way I would expect anyone else to answer it, straight to the point. If you wanted a fucking tutorial, then ask for it, but don't expect an essay on git from a simple question.

    @blakeyrat said:

    The words "before pushing" are in the goddamned title of the page.

    This is done before pushing your changes. After the push you can't do a rebase (Well, you can but that's another thing)



  • @Eldelshell said:

    You asked a question and I answered in the same way I would expect anyone else to answer it, straight to the point. If you wanted a fucking tutorial, then ask for it, but don't expect an essay on git from a simple question.

    Right; but it only works on the local machine, and the question is about the remote.

    @Eldelshell said:

    This is done before pushing your changes. After the push you can't do a rebase (Well, you can but that's another thing)

    THE QUESTION IS ABOUT THE COMBINING COMMITS IN THE REMOTE REPOSITORY PLEASE READ THE QUESTION BEFORE RESPONDING



  • @IngenieurLogiciel said:

    It means you are interactively "rebasing" (restructuring commits - squashing them together, dropping them completely, even editing them and their messages - into a new set of commits with new hashes) the remote branch.

    ... ok? So you can do this on the remote branch?

    What happens to the new set of commits? Do I just need to "push" them back to the remote, or do they need to go into a new branch or...?

    @IngenieurLogiciel said:

    Anyone who has the old commits you already pushed or has merged them in different branches could have problems (e.g. merge conflicts, or the commits could continue to exist in other remote branches or other user's local branches).

    The point of doing this is so the pull request is clean. Nobody would be pulling this branch until it's in pull request form.

    @IngenieurLogiciel said:

    Hopefully this answered some of your questions above and was less gibberish.

    Slightly, but it's still confusing as heck. The StackOverflow link implies that opens a text file? Which I then edit somehow?

    Isn't there just a GUI for this in some tool?



  • Oh! You mean after doing the push... carry on then


  • :belt_onion:

    Am I the first to ask why your boss cares how many commits you have in your PR? It really shouldn't matter... at all...

    Sorry for not being helpful, but it really shouldn't matter... what matters is the diff from HEAD...



  • @blakeyrat said:

    Do you?

    It's all lost for good, I get it, and I understand why you make so many commits. I'd do the same thing. But then I'm not as anal about making the commit history read like a novel like your boss, and would accept your workflow as is.

    I did have an alternate solution, but...

    @blakeyrat said:

    Atlassian Stash doesn't allow that; every commit has to be attached to a Jira ticket. Even if it did, it doesn't solve the problem because:

    @blakeyrat said:

    I have no idea what that means or how to do it.

    Reading about your constraints with git before, I was expecting as much. So I didn't put as much effort into making the alternate solution understandable as I should, because I didn't want to waste too much of your and my time with a solution you couldn't use anyway.


  • :belt_onion:

    @blakeyrat said:

    Who's? Why? How?

    Because when you rewrite history, you run the risk of:

    • screwing over your co-workers' repositories
    • screwing over your repository
    • screwing over the main repository
    • causing unresolvable conflicts
    • obliterating code permanently

    This is because:
    Each commit is a diff between your current code and the last commit.
    If you change the base for a commit, the diff may no longer be valid.
    If the diff is no longer valid, everything goes to hell.



  • @sloosecannon said:

    Am I the first to ask why your boss cares how many commits you have in your PR?

    Well, I can see the point of not wanting stuff like:

    commit 3213213 "Aw god why this doesn't work"
    commit 4324322 "I'll try this now"
    commit 4114322 "Fix ISSUE-123"
    commit 4324322 "Wait no I didnt fix that issue"
    commit asdasda "Fix ISSUE-123 again... for real"
    commit gdfgfdfg "Who changed ISSUE-123 for ISSUE-321??"
    

    And instead:

    commit 7878782 "FIxed ISSUE-321"
    

    I mean, this has happened to me.



  • @blakeyrat said:

    Yesterday my boss griped that my PRs have too many commits in them.

    What kind of crazy person would complain about extra detail? Turning a week's worth the work into one big commit makes it difficult to tell why a change was made. I would much rather see a changed marked as "refactored foo" than be part of a mega-commit with the message "Project #2112".



  • @sloosecannon said:

    Am I the first to ask why your boss cares how many commits you have in your PR?

    His argument is that if we need to remove a portion of the feature, it's difficult to tell which of the commits are relevant to that portion. I do the work in "functional blocks", meaning I generally work one a part of the feature until it's functional, then move on to another until that's functional, etc. But if the commit message is, "commit to switch branches" that's not helpful to figure out why the change is actually there.

    On the one hand I completely get his point. On the other, I'm not sure this ("this" meaning undoing parts of a PR without undoing the whole thing) is something that needs to be done often, or perhaps even at all. On the third, I'm sitting here annoyed once again over everything in Git being so extraordinarily and unnecessarily complicated.

    It's starting to look like what I want doesn't exist.

    @IngenieurLogiciel said:

    Reading about your constraints with git before, I was expecting as much. So I didn't put as much effort into making the alternate solution understandable as I should, because I didn't want to waste too much of your and my time with a solution you couldn't use anyway.

    What I'm looking for is a GUI that resembles the one I drew above.

    @sloosecannon said:

    screwing over your co-workers' repositories

    Co-workers shouldn't have been in my branch before it became a pull request-- at least not without telling me.

    @sloosecannon said:

    screwing over your repository

    How?

    @sloosecannon said:

    screwing over the main repository

    How?

    @sloosecannon said:

    causing unresolvable conflicts

    How?

    @sloosecannon said:

    obliterating code permanently

    How?

    @sloosecannon said:

    This is because:Each commit is a diff between your current code and the last commit.

    Right; but they're all contiguous. As long as you merge the commits in such a way that they're still contiguous, I can't see how this would be a problem.

    @sloosecannon said:

    If you change the base for a commit, the diff may no longer be valid.If the diff is no longer valid, everything goes to hell.

    I'm not entirely sure what "the base" of a commit is, but if you mean the commit that came previously (a.k.a. the commit this one is a diff of), then see above.

    @Eldelshell said:

    Well, I can see the point of not wanting stuff like:

    commit 3213213 "Aw god why this doesn't work"
    commit 4324322 "I'll try this now"
    commit 4114322 "Fix ISSUE-123"
    commit 4324322 "Wait no I didnt fix that issue"
    commit asdasda "Fix ISSUE-123 again... for real"
    commit gdfgfdfg "Who changed ISSUE-123 for ISSUE-321??"

    And instead:

    commit 7878782 "FIxed ISSUE-321"

    I mean, this has happened to me.

    Exactly. This doesn't seem to be a weird question (to me at least). The weirder thing is that it doesn't exist.

    @Jaime said:

    What kind of crazy person would complain about extra detail?

    Read the OP. "Commit to change branches" is not useful detail to have in the development branch's history, and I 100% agree with him.


  • :belt_onion:

    @blakeyrat said:

    Right; but they're all contiguous

    Here's the issue. When you rewrite history, they aren't any more. All bets are off. That's exactly why you shouldn't do it! When history is re-written, your version control goes from a reliable, nothing-ever-gets-deleted source storage system to something significantly less reliable. Before you ask why it's even a feature, it's there for rare cases where you really, really do need to remove something completely, like if you need to completely rebuild your repository or someone committed a password to the repo or something. It should never be used on a regular basis, that's just asking for all the above issues.



  • @blakeyrat said:

    ... ok? So you can do this on the remote branch?

    What happens to the new set of commits? Do I just need to "push" them back to the remote, or do they need to go into a new branch or...?

    On the branch you want to clean up commits:

    $ git rebase -i HEAD~n
    

    where n is the number of commits back in history, starting with the most recent (HEAD), you want to change. 2 would get you the top 2 commits, 3 would get you 3, etc.

    It will prompt you with a commit message text file that you can edit which will tell the rebase command what to do with each commit.

    Then do:

    $ git push origin branchname --force
    

    Note that lots of remotes reject forced pushes that rewrite history like this, because, as has been mentioned several times in this thread already, it is dangerous. For instance, if you did

    $ git push --force 'Do not do this'
    

    instead, it will rewind the histories of every local remote-tracking branch that you have, for which you haven't done a pull while on that branch recently. tmg;dr It deletes work.

    @blakeyrat said:

    The point of doing this is so the pull request is clean. Nobody would be pulling this branch until it's in pull request form.

    You should be ok then. As long as you don't screw something up.

    @blakeyrat said:

    The StackOverflow link implies that opens a text file? Which I then edit somehow?

    Isn't there just a GUI for this in some tool?

    Yes, it opens a text file. Yes, if you are using the git Bash tool that installs as part of some git Windows installs, it comes up it in vi. You read that right, you are using vi in bash in Windows to edit git commits. No, there is no GUI for this that I know of.



  • @blakeyrat said:

    His argument is that if we need to remove a portion of the feature, it's difficult to tell which of the commits are relevant to that portion.

    Then the problem is that your features aren't broken up enough, not that you have a ton of commits on the branch. If you need to remove a portion of a feature, then that portion should have been on its own branch. Then you just remove the entire branch merge commit.


  • :belt_onion:

    @JazzyJosh said:

    If you need to remove a portion of a feature, then that portion should have been on its own branch. Then you just remove the entire branch merge commit.

    QFFT


  • :belt_onion:

    @Eldelshell said:

    Well, I can see the point of not wanting stuff like:

        commit 3213213 "Aw god why this doesn't work"
        commit 4324322 "I'll try this now"
        commit 4114322 "Fix ISSUE-123"
        commit 4324322 "Wait no I didnt fix that issue"
        commit asdasda "Fix ISSUE-123 again... for real"
        commit gdfgfdfg "Who changed ISSUE-123 for ISSUE-321??"
    

    And instead:

        commit 7878782 "FIxed ISSUE-321"
    

    I mean, this has happened to me.

    That's pretty much the entire purpose of PRs and merge commits ;)



  • @blakeyrat said:

    Read the OP. "Commit to change branches" is not useful detail to have in the development branch's history, and I 100% agree with him.

    To be fair, the OP had two reasons for extra commits and change branches was #1. I was referring to #2.

    When you need to switch tasks in the middle of something, why not just make another clone instead of switching branches on the current clone?


  • :belt_onion:

    @Jaime said:

    When you need to switch tasks in the middle of something, why not just make another clone instead of switching branches on the current clone?

    +1.

    Also, wtf git environment are you using where you don't have stash?



  • There are no GUI tools he can use to do git stash, therefore he doesn't use the feature.

    Also, I might get called out on my above post because that won't help at this moment, but that is what I suggest doing going forward. If you want to do it now, then interactive rebase is the way to go.

    Have you looked at this blakey?:

    https://www.youtube.com/watch?v=qi_QAFrmHJM

    This was the 7th result when I googled "git gui interactive rebase" however, I'll give you the benefit of the doubt because you didn't know about that term or process.



  • @sloosecannon said:

    When you rewrite history, they aren't any more.

    They're still there, they just aren't pointed to by the branch you have moved. If you know the hash, you can go back to it until it GCs. If you have another branch or tag at the tip of the original commit sequence, you can use that to go back to it and it will never be GC'd unless that branch/tag is moved or deleted.

    This is kind of nitpicking, but it's also important.

    @sloosecannon said:

    It should never be used on a regular basis, that's just asking for all the above issues.
    I think this is too strong; rewriting history to clean it up is a perfectly reasonable thing to do and can lead to a better source history than otherwise (IMO). It should just be clear what is a development branch subject to being rebased and what isn't. You could even have separate repositories for those.


  • :belt_onion:

    That's true, I probably should've worded it a little differently.

    History rewriting should be done with extreme caution and never done with something someone else might be working on.

    @EvanED said:

    They're still there, they just aren't pointed to by the branch you have moved. If you know the hash, you can go back to it until it GCs. If you have another branch or tag at the tip of the original commit sequence, you can use that to go back to it and it will never be GC'd unless that branch/tag is moved or deleted.

    This is kind of nitpicking, but it's also important.


    Well it depends on exactly how you rewrote history. You can obliterate things permanently if you do the right sequence of mistakes.



  • @sloosecannon said:

    Here's the issue. When you rewrite history, they aren't any more.

    Why wouldn't they be?

    I mean, you're stating this like it's a truism-- I could see how you could screw this up (by combining commits out-of-order) but surely any UI built to accomplish this task could just trivially prevent that from happening with a tiny bit of validation logic, right? I mean it's a pretty damned easy mistake to catch, right? Am I crazy here?

    @sloosecannon said:

    All bets are off. That's exactly why you shouldn't do it!

    Because the UI for it is crappy and error-prone?

    Ok someone move this out of Coding Help because now it's becoming a rant.

    You're saying this extremely trivial operation "shouldn't" be done, but the only reasoning I can come up with to explain why it shouldn't be done is, "because Git is stupid and doesn't validate its inputs." Seriously? Is that the answer?

    @IngenieurLogiciel said:

    It will prompt you with a commit message text file

    I don't know what that means. How do you get "prompted" with a text file?

    @IngenieurLogiciel said:

    You should be ok then. As long as you don't screw something up.

    Well I can guarantee if it requires the CLI and things like, "prompting" me with a text file, I'm not even going to attempt it.

    @IngenieurLogiciel said:

    Yes, it opens a text file. Yes, if you are using the git Bash tool that installs as part of some git Windows installs, it comes up it in vi. You read that right, you are using vi in bash in Windows to edit git commits.

    ... have I mentioned recently how many people tell me Git is a good high-quality tool? Christ.

    @IngenieurLogiciel said:

    No, there is no GUI for this that I know of.

    Of course not. :(

    @JazzyJosh said:

    Then the problem is that your features aren't broken up enough, not that you have a ton of commits on the branch. If you need to remove a portion of a feature, then that portion should have been on its own branch. Then you just remove the entire branch merge commit.

    If my boss presses me on the matter, I'll make that argument.

    I'm guessing it's likely that the need he anticipates has never actually happened before. I could be wrong.

    But, again, I also agree that having junk commits in the development branch is stupid.

    The problem is, with Git, there's no way to secure code on the server without creating a commit message! What a terrible design. This goes back to my "Git having the feature to work offline == good; Git FORCING people to work offline even when they don't want to == terrible" argument.

    @Jaime said:

    When you need to switch tasks in the middle of something, why not just make another clone instead of switching branches on the current clone?

    Because then I have to keep track of the mental baggage of which of the 4 clones are on which branch at any given time. Also I need to wait 2+ hours per clone for them to download. Also the "open recent project" menu in Visual Studio becomes completely useless, because God knows which clone I'd get. Also I can't set up my projects to be hosted in IIS, because I'd have to change the paths in IIS based on which clone I'm working on at the moment and/or I'd have to set up a site on IIS for each clone for each repo (currently: 16), then somehow memorize the IPs for every one of those sites.

    I can probably think of more reasons if you give me a few minutes.

    @sloosecannon said:

    Also, wtf git environment are you using where you don't have stash?

    Visual Studio's Git client and GitHub for Windows both do not support stash.

    @JazzyJosh said:

    There are no GUI tools he can use to do git stash, therefore he doesn't use the feature.

    I think SourceTree does, but SourceTree is a terrible confusing mess. The reason I don't use the CLI is because it's accident-prone and I'm terrified of deleting work-- SourceTree's UI is so godawful, confusing, and broken that I have the exact same problem with it.

    @JazzyJosh said:

    Have you looked at this blakey?:

    No, but SmartGit is the client written in Java which I refuse to install.



  • Two possible workarounds, since you really describe two problems:

    (Not sure if this one will work for you, but) have different branches checked out separately on your machine. That would avoid the 'switch branch commits'

    Use tags to flag your 'full' commits, to differentiate them from your intermediates.

    if you have any poo, fling it now! 🐒

    edit hanzo'd about the first solution. Won't work for you, then. Tags might still help, though.



  • @sloosecannon said:

    You can obliterate things permanently if you do the right sequence of mistakes.

    But it's hard. You have to trigger garbage collection, or delete that repository. Now, it might not be trivial to figure out what to restore to, but IME it's almost always possible.


    I would say this. I don't know how to do these things in your GUI, but if you can do them here is how you can clean up:

    • Tag your current state (this solves the GC and "where do I restore to" problem)
    • Do an interactive rebase
    • When you are satisfied, make your PR; after it is accepted, delete the tag
    • If you screw up, "reset" the branch to the tag

    If you're pushing to a branch that only you are likely to be using, feel free to push the rebased branch (forcing it). If there's a reasonable chance it'll be shared, don't.

    @blakeyrat said:

    I mean, you're stating this like it's a truism-- I could see how you could screw this up (by combining commits out-of-order) but surely any UI built to accomplish this task could just trivially prevent that from happening with a tiny bit of validation logic, right? I mean it's a pretty damned easy mistake to catch, right? Am I crazy here?
    First, reordering commits is one of the main reasons you might want to rebase, so "preventing" it wouldn't be so useful. One of the options is "squash"; if all you do is squash, then there should be no problem.

    Second, even if all you do is squash commits, you're still changing things. Your branch used to have commits A -> B -> C -> D on it, and now it has AB -> CD if you squash A and B and squash C and D; if all you have is AB -> CD you can't get back to A -> B -> C -> D. That's what @sloosecannon & others mean when when they say rewriting destroys history. Furthermore, if someone has the A -> B -> C -> D view and then you force push it to AB -> CD and they pull, they will have to do some manual fixup if they want to incorporate your changes because automatically updating their local copy will "destroy information" in that sense, so Git doesn't do it; that is why people caution about pushing rebased branches.


  • :belt_onion:

    @blakeyrat said:

    You're saying this extremely trivial operation "shouldn't" be done, but the only reasoning I can come up with to explain why it shouldn't be done is, "because Git is stupid and doesn't validate its inputs." Seriously? Is that the answer?

    You're confusing what I'm talking about.

    What you want to do is remove commits.
    That involves rewriting history.
    You should never, ever be rewriting remote history, because it will screw with everyone else in the project by breaking their repository. Most source control hosts actually don't allow history rewrites at all for exactly this reason. Remote history rewrites are basically the non-user friendly admin tool to fix some major f**kup someone did, so they aren't exactly designed to be user-friendly.

    Blakey, remember that git is distributed vcs. Even if someone else isn't working on a branch, when they pull, they'll get that branch's history. If you change it, by squashing the commits, they now have a bad repository that doesn't match with the main repo. So either they overwrite your work, by doing a push --force, or you overwrite theirs by making them reset their repository.



  • @blakeyrat said:

    No, but SmartGit is the client written in Java which I refuse to install.

    Well a quick search doesn't turn up other options so it looks like your only options are ^ and using the CLI. Or using the portable SmartGit so you don't actually install Java.



  • @sloosecannon said:

    There is a way to work around this. Rebase can do exactly what you want, but you can't use it remotely. In other words, you need to rebase before you push, so your history rewrite is local not remote.
    I still think this needs to be revised to before you push to a branch that is likely to be shared between people. If you just have a remote branch that is just backup of the branch you're working on locally, and you push to it and rarely or never pull, then there's no problem. If you do pull into different repos (e.g. on different machines) you'll have to be prepared to deal with the fact that Git won't auto-merge the rebase. If other people pull from it but are aware that it's in active development and subject to be rewritten, there's also no problem.

    @sloosecannon said:

    So either they overwrite your work, by doing a push --force, or you overwrite theirs by making them reset their repository.
    Again, I think "overwrite" is too strong of a statement. You won't destroy their work either in the short term or long term. Furthermore, if the end result of the rebase hasn't changed (as is the case when you just squash commits, but other times as well), copying changes from the original to the rebased branch is easy. Even more than that, if the rebase did change the end result, then it basically becomes just the same as the usual conflict-resolution process.


  • :belt_onion:

    Well if they force push it will actually overwrite stuff, since you're completely replacing the repository with your own...



  • @sloosecannon said:

    Well if they force push it will actually overwrite stuff, since you're completely replacing the repository with your own...
    Sure, that's true if you push to the repo they're actually working on (subject to the "GC" comments above), but who actually pushes to a repo that is actually used? If you're using Git in a centralized-ish fashion, you'll push and pull from a repo that is almost certainly unused for developing (and should be bare). The other developer's work will still exist in their repository. If you're using it in a distributed fashion, almost everything will be pull requests and, again, you're not pushing to an in-use repo.


  • :belt_onion:

    Here's an analogy to try to explain what happens here.

    Let's say I'm traveling to Hawaii by plane. I have a flight from Dayton, Ohio to San Francisco, California, then I switch to a San Francisco to Honolulu flight. While I'm in San Francisco, I stop by at a local restaurant and grab a burger, paying with my credit card. Now, what your boss is saying is "I think having 2 flights is too complicated, just say you flew from Dayton straight to Honolulu." You can say that, but then what does the credit card statement for the burger represent? I never was in San Francisco, so how could I have a card swipe there?


  • :belt_onion:

    Actually, yeah, I don't even think what he wants to do is possible, if they're using pull requests. Because that means they can't remote history rewrite, since the only person with full access to the repo is the boss. So the whole point is moot I believe... (or at least it is if they're being sane about permissions...)



  • But he can rewrite his branch before creating the PR.


  • :belt_onion:

    Can he? My understanding was that it would affect the whole repository.
    I may be wrong on that point, haven't really delved into the internals of git all that much.



  • @blakeyrat said:

    Because then I have to keep track of the mental baggage of which of the 4 clones are on which branch at any given time. Also I need to wait 2+ hours per clone for them to download. Also the "open recent project" menu in Visual Studio becomes completely useless, because God knows which clone I'd get. Also I can't set up my projects to be hosted in IIS, because I'd have to change the paths in IIS based on which clone I'm working on at the moment and/or I'd have to set up a site on IIS for each clone for each repo (currently: 16), then somehow memorize the IPs for every one of those sites.

    I can probably think of more reasons if you give me a few minutes.

    I'm not sure if it's as much "doom and gloom" as you think it would be. This is how I've always worked with multiple branches; in VSS, then SVN, and now TFS. Visual studio project history is actually clearer this way because it's obvious what you get when opening "C:\work\project1\branchx\stuff.sln" vs "C:\work\project1\branchy\stuff.sln". I purposely use the ASP.Net dev server instead of IIS because it handles this incredibly well. The dev server also does check-out-and-run better since it doesn't depend on anything; anyone can open the project, whether or not they have IIS installed, or even if they're a non-admin on their computer.



  • @sloosecannon said:

    My understanding was that it would affect the whole repository.

    Just the branch that is being force-pushed.

    I suppose there's a tiny bit of danger in that if he were to accidentally or intentionally rebase a branch he shouldn't and then accidentally push both it would cause problems, but that seems (1) unlikely and (2) recoverable.



  • @EvanED said:

    First, reordering commits is one of the main reasons you might want to rebase, so "preventing" it wouldn't be so useful.

    Not only do I not want to do that, I also can't imagine any scenario in which I would want to do that.

    @EvanED said:

    One of the options is "squash"; if all you do is squash, then there should be no problem.

    I think that's the oh-so-cute term Git uses for what I want to do, but, again, it only works locally. Once you've pushed to the server, you're sunk. But if you don't push, and your laptop HD dies, you're also sunk. I don't like lose-lose situations.

    @EvanED said:

    Second, even if all you do is squash commits, you're still changing things.

    Duh?

    @EvanED said:

    Your branch used to have commits A -> B -> C -> D on it, and now it has AB -> CD if you squash A and B and squash C and D; if all you have is AB -> CD you can't get back to A -> B -> C -> D. That's what @sloosecannon & others mean when when they say rewriting destroys history.

    That's not a big deal, as long as the code's all safe. I don't care about getting back to the "switching branch" commit or the "leaving for the day" commit-- I'd rather not have to make them in the first place!

    @EvanED said:

    Furthermore, if someone has the A -> B -> C -> D view and then you force push it to AB -> CD and they pull, they will have to do some manual fixup if they want to incorporate your changes because automatically updating their local copy will "destroy information" in that sense, so Git doesn't do it; that is why people caution about pushing rebased branches.

    Again, if some random dude is in my branch before I create the PR, and they didn't let me know, we have bigger problems.

    @sloosecannon said:

    You're confusing what I'm talking about.

    What you want to do is remove commits.That involves rewriting history.

    Right-- remove commits, but not remove changes. Right.

    @sloosecannon said:

    You should never, ever be rewriting remote history, because it will screw with everyone else in the project by breaking their repository.

    How would it affect anybody except the person in the same branch as me?

    @sloosecannon said:

    Most source control hosts actually don't allow history rewrites at all for exactly this reason. Remote history rewrites are basically the non-user friendly admin tool to fix some major f**kup someone did, so they aren't exactly designed to be user-friendly.

    Then what do "normal" Git users do about all the junk, "taking my laptop home for the day" commits? Just leave them in place?

    @sloosecannon said:

    Blakey, remember that git is distributed vcs. Even if someone else isn't working on a branch, when they pull, they'll get that branch's history. If you change it, by squashing the commits, they now have a bad repository that doesn't match with the main repo. So either they overwrite your work, by doing a push --force, or you overwrite theirs by making them reset their repository.

    So it's a bug?

    I get what you're saying, I don't see how it relates to Git being distributed, and I don't see why it's impossible for Git to handle this situation in a clean matter. (Just tell the client: oh BTW, commits A B C D are now commits AB and CD, here are some new IDs and messages, k thx bye.)

    @JazzyJosh said:

    Or using the portable SmartGit so you don't actually install Java.

    Java is Java.

    @EvanED said:

    I still think this needs to be revised to

    @sloosecannon said:

    Well if they force push it will actually overwrite stuff,

    Look, you guys are way overthinking the problem here.

    The problem is: how do I check-in code to ensure it's safely stored on the server without polluting the hell out of the branch's history?

    I don't care about any of the details. What's mind-boggling is this has to be an extremely obvious problem, but there doesn't seem to be any solution to it other than "well just pollute the history, we don't support that." That's crazytalk.

    @EvanED said:

    But he can rewrite his branch before creating the PR.

    Yes! That's the question in the OP nobody read! How do I do it?!



  • @blakeyrat said:

    Atlassian Stash doesn't allow that; every commit has to be attached to a Jira ticket. Even if it did, it doesn't solve the problem because:

    This is actually something your environment has configured -- We run stash/jira here and the two aren't conflated in any way.

    Don't do rebasing like Eldelshell is saying - it's definitely not worth the potential trouble it will cause if you make even a slight mistake.

    When you combine commits, it makes it harder for the diff program to figure out which order changes happened, and can essentially merge changes in the wrong order. Noisy commits suck, but on a whole it's better than the alternatives that stash is offering.



  • @blakeyrat said:

    I think that's the oh-so-cute term Git uses for what I want to do, but, again, it only works locally. Once you've pushed to the server, you're sunk.
    I can't speak to the exact tools you're using, but for raw Git you can certainly do that. That's just where the cautions come in about not pushing to shared branches -- but that's a warning, not an impossibility. If it's just a dev branch for yourself, you can "force" push.

    @blakeyrat said:

    (Just tell the client: oh BTW, commits A B C D are now commits AB and CD, here are some new IDs and messages, k thx bye.)
    Remember, squash is a special case of what you can do with rebasing; rebasing can perform arbitrary modifications to the history. Furthermore, it doesn't even solve the problem, because I might want the original A -> B -> C -> D view, so IMO Git does the right thing by being safe and not just auto-replacing the rewritten history.



  • @Jaime said:

    I'm not sure if it's as much "doom and gloom" as you think it would be.

    Ok...

    @Jaime said:

    Visual studio project history is actually clearer this way because it's obvious what you get when opening "C:\work\project1\branchx\stuff.sln" vs "C:\work\project1\branchy\stuff.sln".

    It just shows on the list as BlorpProject, BlorpProject, BlorpProject.

    And yeah, if you mouseover, you get Documents\Source\Blorp1, Documents\Source\Blorp2, Documents\Source\Blorp3 for the 3 different repos, but that sure as hell doesn't tell you "which of these repos is for bug# 5346?"

    @Jaime said:

    I purposely use the ASP.Net dev server instead of IIS because it handles this incredibly well.

    I concur, but one of the apps I often work on does not support it for reasons I don't want to get into right now.


  • I survived the hour long Uno hand

    @blakeyrat said:

    how do I check-in code to ensure it's safely stored on the server without polluting the hell out of the branch's history?

    According to my devs: by having a VM on the central server hold all your work and tools, and your laptop be a dumb terminal, so you don't have to commit until a feature is done because the work never leaves the building.



  • You could alter the commit messages after the push to make more sense, but then you're still having to do a push --force on the remote branch. Not really that much better than the rebase in the first place.


Log in to reply