Using git pull properly - ruby-on-rails

I am new to git so please bear with me. I have a rails application on my local machine that I am experimenting with and pushing to the master branch periodically. It works at the moment, but I have fallen behind, and now I am many commits behind the master.
$ git branch
* master
$ git status
On branch master
Your branch is behind 'origin/master' by 27 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
However, when I use git pull and then start rails, my application breaks with a precompiler error. So I am forced to use git --reset to go back to the local commit before I used git pull.
What is the right way to get around this issue and merge with the latest changes on the master branch? Would one use git --rebase in this case?

Try
git stash
git pull origin master
And once it updates, git stash apply to reapply your local changes

Since nobody has stated this clearly yet: You ask
What is the right way to get around this issue and merge with the latest changes on the master branch?
When you do git pull that does merge the remote changes into your current branch. Whether you would choose to do a rebase instead of a merge (per your other question) is a separate issue, but the default behavior is to combine the two sets of changes (local and remote).
More precisely, by default git pull does a fetch followed by a merge. The exact merge operation depends on configuration and on command-line options, but in a typical configuration where origin/master is upstream of master, saying
git pull
will merge origin/master into master.
So why the errors?
One possibility is that there were merge conflicts. If that happens, git will tell you. If you say git status in this condition, it will tell you that there's a merge in progress and it will indicate which paths (files) need conflict resolution.
Another possibility is that the changes don't conflict (in that they don't affect the same region of the same file) but still don't work properly together. That you would simply have to debug.

Related

Git commit and then pull in branch, from master. Loosing everything?

I am working on a completely different structure from the one on master branch, on a On Rails app in a local branch. I am comiting everything and then pushing my changes to a remote branch as well. At some point in future, I would like to integrate my changes back into master, but I want to make it even first, so I won't be behind it, just ahead by n commits. If I am doing a
git pull origin master
into my branch and then push that, would I loose anything from my previous commits, or would those stay on top of the master branch ones? In theory I should be able to merge my branch, as I will only be ahead of master, but I am not entirely sure if that's how git is working
Never do significant work on the master branch. The only time you are really working on the master branch is when you are merging or if you are the lone programmer on a project (even then its questionable).
When working on a feature or taking care of a bug you want to be working on a separate branch.
For example when I take an issue from the product tracker I create a topical branch based on the name of the issue:
git checkout -b 136-fix-something-important
If the work on a topical branch takes a long time you keep up to date with the remote by pulling the changes into the master branch and rebasing your topical branch off master.
git status # make sure you have a clean slate otherwise stash or commit
git checkout master
git pull
git checkout 136-fix-something-important
git rebase master
This would fast-forward 136-fix-something-important if there are no conflicts or you would have to resolve the conflicts. However taking care of conflicts is better done early that later in a mega merge.
When you are done with the feature in your topical branch you either merge it (if you are a maintainer) or send a pull request (if you are a contributor).
So what do I do now?
Move your work to a separate branch. And reset your local master branch from origin/master:
git branch mybranchname
git reset --hard origin/master
git checkout mybranchname
You can the rebase your work in mybranchname off master.
git rebase master
Other answers aren't wrong, but it would be cleanest to push to a remote branch, pull to local master from remote master, then locally merge master into your local feature branch.
Then, your changes wouldn't be lost, merge conflicts could easily be resolved, and you won't rewrite any other potentially collaborative history with rebase.
you will not lose data when you do a PULL but you will get merge issues which you will need to fix.
While technically you can push without pulling (with --force flag), you should not do that, because it discards other people's work. First pull their changes, resolve conflicts and only then you can push.
Piece of advice, try to make your units of work small, as in don't spend too much time away from master especially if master gets updated frequently. The reason is that you will have a very difficult time merging.

Git Squash and remove previous commits

Maybe I misunderstood how GIT works.
I've run git rebase -i HEAD~10 and I could squash 10 commits into one. The issue is that all squashed commits are still there, and I thought they were going to be dropped after merging them all into one.
Is this the expected result? If so, can I rewrite the history to remove useless commits (since these changes are already in the commit which all previous commits were squashed)?
When you began your interactive rebase session, you should have been prompted with a list of the last 10 commits from the current branch:
git rebase -i HEAD~10
pick as2i8dw first commit
pick ee361eb second commit
...
pick b2762sx most recent commit
You need to change this file to the following:
pick as2i8dw first commit
squash ee361eb second commit
...
squash b2762sx most recent commit
Then you need to do a git commit to save the changes. Now when doing a git log you should only see the as2i8dw commit and none of the other ten.
That being said, is this what you did?
The issue is that all squashed commits are still there
If those commits are still accessible by any other reference (other branch or tag), there would still be visible, even after the current branch is rebased.
Try instead squashing the commits with a git reset --soft.
If HEAD does still reference your 10 commits:
git reset --soft HEAD~10
git commit -m "squashed 10 commits"
I faced the similar issue and figured out the actual cause for it:
The flow:
git rebase -i HEAD~10
# Retain the first commit from below( as pick) and change the rest of the `pick` to `squash`
# After your rebase is successful
git log
# You can see all your commits squashes to one commit
Then now when you git pull from your remote branch, it will pull the rest of the commits which is not there in local ( basically all the commits you had squashed previously, since it is now present in one commit) and hence you are seeing the previous commits as well.
Better way is to git push -f to your remote branch, if you are confident that you have no new changes added there.
P.S: If you have any new changes in the remote branch, better to:
git rebase origin remote_branch
and then squash your commits.

I need to apply a hotfix to production but I didn't create a branch, what can I do?

I started working on a bunch of new features in the code without branching.
Those new features are not ready to deploy. However, an urgent request has come in to fix a different issue.
I'd like to go back to the version before I started adding the new features, apply the fix there, and then deploy.
However, I'm confused as to which one should become a branch, and which version should merge to which.
Can someone provide me with a solution to this problem, as a step by step git process to get this done.
Note, I've never branched on source control (now I see why I should have)!
This is one way, there might be an easier one. This also assumes that the changes you made are only local on your machine and not pushed to any remote branches.
Lets say we have
master
|
A - B - C' - D'
where C' and D' mark commits with the new features, which you don't want to deploy.
First, create a new branch at the current commit (master):
git branch new_feature
Now we have to pointers to the commit D', master and new_feature. This is important to not loose any of the changes you already did.
master
|
A - B - C' - D'
|
new_feature
Now we want to reset the master branch to a state without new features, i.e. to commit B We can do that using git reset --hard.
Important: If you have uncommitted changes at this point, they will be lost. I recommend to read this excellent article about git reset, to understand what it is really doing.
git reset --hard B
The structure will now look like:
master
|
A - B - C' - D'
|
new_feature
On the master branch, you can now make your hotfix changes (commit E) and push them to heroku:
master
|
A - B - E
\
C' - D'
|
new_feature
Then you can either merge the hotfix into the new_feature branch, or just rebase it on top of the hotfix:
git rebase master new_feature
which results in:
master
|
A - B - E
\
C' - D'
|
new_feature
The Pro Git book is a really good source to learn Git, and it's free: http://git-scm.com/book.
What I would do is create a branch from your current state as a feature branch so you don't lose any work.
git checkout -b new-features && git push origin new-features
Now that you've saved your current state to a branch (and pushed it to the remote), git checkout your original branch and revert it back to a point before your current head.
The best way to do this is to use git revert. A good explanation on why and how can be found on: Revert multiple git commits.
Once you reverted the changes, committed, and pushed, I'd recommend you create a branch to develop the bugfix on. This is good practice for the same reason people create feature branches. A good rule of thumb is to create a branch with the same or similar name / number as the issue you are working on. Do all of your changes on there and when it's all done, you can pull it in to whatever branch you are tagging your deployments from.
The best part about this is that it works whether or not any changes have been pushed to a remote, is simple and follows best practices.
Hope that helps.
EDIT: To answer question in comment.
"This also assumes that the changes you made are only local on your machine and not pushed to any remote branches."
That method will not work if you've already pushed. There are ways around it, but I wouldn't recommend it.
Basically, the only difference between the two methods at their core is that one does git reset --hard [commit] and the other uses git revert. Resetting actually tells git to go back to a particular commit, which is essentially the effect you want, but is frowned upon if you've already pushed. Since git will not allow a push to have non-fastforwarding changes and you have actually erased history, you'd have to do a git push origin [branch] --force causing the remote to also lose the changes.
Revert actually creates a commit that adds history to git about the commits you are undoing. This is better because all reverted changes can be tracked and anyone who has pulled from that branch will not become out of sync. They will get the revert, or reverts, when they pull. A good side effect of this is that if you make a mistake in your reverted change, you can revert it later since it is just another commit.
I started working on a bunch of new features in the code without branching.
Assuming you haven't committed any of them, you could commit them on a temporary branch.
git checkout -b temp_work
git commit -am "temporary work"
Then you could checkout master again, branch from there and do your urgent work there.
git checkout -b urgent_work
When you're done with, passes its tests etc, then merge it back to master
git checkout master
git merge urgent_work
you can create a new branch now, like git checkout -b my_current_work, then you can go back to master - git checkout master, and go back to the commit which was deployed [ I hope you remember ]. You can use for example gitk command to see the graph and get the hash of the proper commit. After that you can either git checkout hash_of_the_commit or git reset --hard hash_of_the_commit ( I would recommend checkout, it is safer I believe ). If it was the previous commit, you can always use syntax like git checkout HEAD~1, where ~1 means previous commit, ~2 would mean second last commit etc. Your whole work should be still in the "my_current_work" branch, so you will not lose anything. Just make sure you commit all your changes before creating new branch.

git pull from a github repository fork gives conflicts

I have forked rails git://github.com/rails/rails.git at github. My forked repository is at git://github.com/waseem/rails.git. I want to test out some patches submitted by other users to rails mainline. Lets say I want to test out code in migration_status branch at git://github.com/joelmoss/rails.git.
Lets say I
master $ git remote add joelmoss git://github.com/joelmoss/rails.git. and
master $ git remote add mainline git://github.com/rails/rails.git.
I have been pulling from rails mainline into my master.
master $ git pull mainline master
According to http://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#testing-patches I should create a local topic branch and pull in changes from joelmoss/migration_status. So I,
master $ git checkout -b migration_status Create a local topic branch.
And when I do:
migration_status $ git pull joelmoss migration_status
I get a large number of conflicts. I also tried migration_status $ git pull --rebase joelmoss migration_status but I still get conflicts.
In the case of pull --rebase, I think (correct if wrong), git is trying to apply my local changes on top of changes fetched from joelmoss/migration_status. Ideally it should do the opposite. To consider this option, I did following.
master $ git fetch joelmoss
master $ git checkout -b joel_migration_status joelmoss/migration_status and
joel_migration_status $ git rebase master it still gave me lots of conflicts.
How do I pull in patches submitted to one of my local topic branches w/o getting conflicts? I can not resolve those conflicts as I do not know much about what code to keep what not to.
In this case, it looks like joelmoss/migration_status is based off of 3.1.0, which split from mainline/master back in May. So if you merge you're trying to reconcile 4 months worth of development by everyone, in branches that appear to never have been intended to merge.
What you want to do is base your local changes on 3.1 as well. That doesn't guarantee to remove all conflicts, but at least it should be ones you are aware of because it's code you changed directly.
git checkout -b master-3-1 master
git rebase --onto joelmoss/migration_status mainline/master master-3-1

Git checkout <SHA> and Heroku

I created a local Git repo on my laptop and then pushed the source to Heroku creating a remote branch. After a few days of commits and pushes, I need to rollback to an earlier commit. Here's what I did.
cd <app root>
git checkout 35fbd894eef3e114c814cc3c7ac7bb50b28f6b73
Someone told me that doing the checkout created a new working tree and not the branch itself, so when I pushed the rollback changes to Heroku, it said everything is up to date and nothing was pushed. How do I fix this situation? Thanks for your help in advance.
When you checkout a direct commit name (using the SHA-1 hash of the commit object) instead of checking out a branch name, you end up with a “detached HEAD”. HEAD is the “ref” that keeps track of what is currently checked out. It becomes detached when you directly checkout a commit instead of a branch (it is not attached to any branch). No branches are updated when you detach a repository's HEAD. You might think of the detached head state as if you had an anonymous branch checked out.
To reattach your repository's HEAD, you will want to save the current HEAD as a branch and check that branch out:
To save the current HEAD in a new branch do this:
git branch <new-branch-name>
To overwrite an existing branch you need to use --force:
git branch --force <existing-branch-name>
Then, reattach your repository's HEAD by checking out the new/updated branch:
git checkout <branch-name>
(where <branch-name> is the same as <new-branch-name> or <existing-branch-name>, depending on which of the above two commands you used)
This sequence (git branch to make a ref point to the current HEAD commit, then git checkout that updated branch) will carry forward any uncommitted content that you might have in your working index and/or tree.
In the future, if you want to ‘roll back’ the current branch to some previous commit, you should use this instead of detaching your repository's HEAD:
git reset --hard <commit>
This will reset the current branch (or your detached HEAD, if it is already detached) to the named commit, and make the index and the working tree reflect that commit (i.e. it throws away any commits since the specified commit along with any uncommitted content).
The detached HEAD state is useful for revisiting old states, and sometimes for short-term work that you are not sure you will keep. Other than that you probably want to avoid it.
You want to reset:
git reset --hard 35fbd894eef3e114c814cc3c7ac7bb50b28f6b73

Resources