Filetree is not refreshing after switching branches - cloud9 - ruby-on-rails

In cloud9 IDE, I am doing simple rails app in master branch. I decided to experiment a little, so I created new branch like this:
git checkout -b experiment-branch
Then I created some controllers, models etc. but experiment fails and I do not committed it. However I dont't want to delete this branch, so I tried to go back to master:
git checkout master
and code (controllers, models etc) from the previous experiment was still there in filetree, ApplicationController etc.
I tried git reset --soft <desired-previous-commit-hash> but it not worked.
I assume the second command should return me the state of my app from before creating the branch experiment-branch. Am I right or I do something wrong?

If you have not tracked the new files you add in the experiment-branch - these are still lying around as untracked files.
Untracked files are not removed when you change branches.
You would need to clean them to remove the untracked files. use git clean -n (dry-run) to identify all the files that are untracked.
Then you could git clean -f to clean all the file shown in the dry-run. Or you could use the interactive mode git clean -I
To revert changes from tracked files, use git checkout .
Refer this post for more details.

Related

How can I un-nest a Git repository

I accidentally did a git.init on a parent folder of my app (Rails project). I didn't realise until a long way into my development when I now wish to deploy to Heroku.
My folder structure is ~/project/project/app with git initialised in ~/project/app.
Heroku states:
"Heroku apps expect the app directory structure at the root of the
repository. If your app is inside a subdirectory in your repository,
it won’t run when pushed to Heroku."
So, I'm trying to undo this, without much success.
I tried moving all the folders of my app up a level, so from project/ I did the following command:
mv project/* project/.* .
This seemed to move a copy of everything up a level, into my ~/project folder, however, in terms of Git, only the still nested files (in ~/project/project/) are the branch specific files (as tested by switching branches and looking at both sets of files in my text editor).
I copied the files when my git branch was specified as the master branch. Does this mean I've only copied the "master branch" files. This is where my knowledge of git is limited.
Any help much appreciated.
** note, i have a copy of my folder or can re-clone from github.
If you don't have a problem to re-publish your repo (git push --force, meaning you will change the history of commits, and other will have to fetch and reset their local branches), you can refer to "How can I move a directory in a Git repo for all commits?".
Use git filter-branch in order to affect all commits of all branches:
git filter-branch --tree-filter \
'test -d project/app && mv project/app . || echo "Nothing to do"' HEAD

Git merge conflict with workspace.xml

I'm trying to push my Rails project to Heroku, but Git isn't allowing me to do anything at the moment. Here's what I've done so far:
git push heroku failed because the heroku branch was "ahead" of my local branch, which should not have been possible.
I pulled and there was a conflict with .idea/workspace.xml. I wasn't able to find out what that file is, but it's huge and Git wrote all kinds of garble to it. Too much to manually "resolve" conflicts.
I saw some stackoverflow posts talking about git-ignoring that file (maybe it's some IDE file for RubyMine or something?), so I tried to move the file away to avoid the conflict
I ran git add -A (also tried git add . and git add)
git commit --amend fails because "You are in the middle of a merge"
git merge --abort fails because "Untracked working tree file '.idea/workspace.xml' would be overwritten by merge (despite the fact that the file has been moved)
git reset --merge fails for the same reason.
How can I make Git work again?
.idea/workspace.xml
This file is your idea workspace files. They are generated by IntelliJ tools.
I saw some stackoverflow posts talking about git-ignoring that file (maybe it's some IDE file for RubyMine or something?), so I tried to move the file away to avoid the conflict
Simply add the folder to your .gitignore but since its already committed you will have to remove it from the repository:
# Quit the merge
git merge --abort
# remove the whole folder from the repo
git rm -rf --cached .idea/
# add it to the .gitignore: idea/
# add and commit your changes
git add .- A
git commit -m " Removed idea folder"
git push origin <branch>
If you still unable to do it?
First reset the code to the previous state and then do the above code again.
The reset will take you to your last commit before the pull
git commit -am "message" worked (as opposed to amending a commit)
I have resolved a similar problem by simply deleting the workspace.xml file. By building and running the program again idea will autogenerate a compatible file.

Ruby on Rails - Git Branch Workflow

I know its a simple concept but just not grasping it after researching several sites.
I have a Ruby On Rails project and using git to manage the source. I have a production ready snapshot and initialize git such that it has a master (with git init, git add -A and git commit -m).
Now I want to try out a new feature so I create a branch called 'test' with git checkout -b test
Now while in test I try out a new scaffold with rails g scaffold UserToken username:string
Scaffold created all of the ROR files and I do a rake db:migrate to update the DB. I then go into the rails console and test out adding records to the db and then start working on updating the other generated scaffold model file.
After lunch I come back and decide I want to scrap all of this.
Questions - (after trying this out myself) is the only way to get back to master is to git add -A, git commit -m and then git checkout master ? Do I really have to add and commit to get back to master? (this does work; however I don't think I'm grasping something basic in git that I would do a commit on something that I am going to scrap)
Next, if I do the above (again I don't think that's right) when I get back to master I do see that my scaffold files are gone as are the migration file (which created the table) and the schema.rb reflects that the table generated while in the branch is not there.
So far so good:
HOWEVER, if I go into the actual database the table IS still there. What basic fundamental am I missing in ROR/Git of testing something out in a branch and then abandoning it?
UPDATE #1
So Stash does not appear to help:
Stash does not help.
Steps:
rails new test_app
git init
git add -A
git commit -m 'initial commit'
git checkout -b newfeatures
rails g scaffold UserToken username:string coin:integer
files get generated...
sqlite3 db/development.sqlite3 show that there is now a table called user_tokens:
git stash save
git checkout master
Now in Master however all of the scaffold files still exist (and shouldn't)
You have two questions here:
First: How do I move between branches without commiting work in progress?
To move between branches without having to commit your work you can use git stash.
git stash help
Usage: git stash list [<options>]
or: git stash show [<stash>]
or: git stash drop [-q|--quiet] [<stash>]
or: git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
or: git stash branch <branchname> [<stash>]
or: git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] [<message>]]
or: git stash clear
Once you stash your work then you can switch between branches without problem. Note that files that you wish to stash must first be added to a git branch via git add. Changes to files, including creation, that have not been added to git are are not tracked. So they are just like any other part of the general file system and will remain visible across branches.
Second: Why do my database migration changes in one branch show up in another?
Because the Database manager is not part of git. Whatever DBMS you are modifying those changes are persisted through the DBMS. If you want to keep your branch migrations separate then you need to have a separate database instance for each.
It may help if you imagine a git branch as a file-system template. When you switch to another branch then that branch's template overwrites your existing file-system with whatever is under its control. Everything else is ignored. When you commit you are updating the template for that branch. However, all of your work is actually done in the one true file-system.
What this means that things that you do to the file-system that are outside of git's control remain visible from all branches.
git reset --hard HEAD deletes everything and goes back to head in your testbranch so you can easily switch back with git checkout master
rake db:reset should do the trick with your data in the DB
UPDATE:
If you really want to get rid of anything:
git reset --hard && git clean -dfx
rake db:drop
rake db:create && rake db:migrate

Starting over with Git

I decided to learn how to use Version Control over Christmas break, so I downloaded Git, opened a GitHub account and started reading the online tutorial linked to from the GitHub website. When I got to this part http://progit.org/book/ch2-2.html I got stuck because I wasn't sure how to add files. For instance, I tried
git add C:/Finish.txt
And it said
Fatal: 'C:/Finish.txt' is outside repository
I was confused until I remember that a long time ago I had tried teaching myself Ruby on Rails and played around with Git back then. It never really went anywhere, but there's all this residual stuff floating around my system and I don't know how to change it. For instance, my Untracked files (which should be empty) are rails_projects/ and sample/.
How can I just erase all the old stuff and start over?
You should make a folder for your repository, move Finish.txt to that repository, then do git add.
For example:
# here you create C:\myrepo
cd C:\myrepo
git init .
# here you edit C:\myrepo\Finish.txt
git add Finish.txt
git commit -m "Added Finish.txt"
Start a new repository, e.g.
c:
md c:\newrepo
cd c:\newrepo
git init .
copy \Finish.txt .
git add Finish.txt
git commit -m "started over"
I strongly recommend against adding anything to C:\, let alone putting a git repo there. Unless of course you want to accidentally add all of your system disk to git :)
I can also heartily recommend using TortoiseGit which has some excellent explorer integration.
Delete any .git folder that you find in your drive.
To create a repo go to a folder that you want the repo in ( and not just randomly), do:
git init
Then proceed... Add only files that you put within this repo and not randomly from some location.
It would be very unusual to have the root directory of your hard drive be a git repository. That's probably why it's giving you the error.
git repositories are typically in a subdirectory and that subdirectory is typically a project.
To initialize a subdirectory as a git repository, you'd do:
git init (directory)
Then you'd add your files and commit.

how do I deploy multiple branches to different directories via git push?

In production, I maintain two sites - beta and release. Each points to a different directory via a soft link (e.g.)
beta_public_html -> /home/scott/myapp/trunk/public
public_html -> /home/scott/myapp/branches/1.2.3/public
I'm a longtime svn user, moving to git. I'm used to deploying via svn update and changing the soft link on a new branch, things are pretty simple.
Now I'm moving to git. I still need to have the two soft links (it's a Rails app using Passenger), though now I want them to point to two different git branches ("beta" and "release", say). And I want to be able to update them via git push (or git pull).
Question Part 1: I'm not sure the best way to do this.
The way I had started to do it was to just deploy to two different remotes, e.g.
git push ssh://scott#x.com/home/scott/myapp-beta beta
git push ssh://scott#x.com/home/scott/myapp-release release
But this doesn't work because push doesn't update the working tree by default.
So I go into the remote directories and run git reset --hard the first time, and it pulls the working tree. But I push again and I can't get the new push to show up - it just stays at the initial one.
(BTW, note that I can't seem to push to "myapp-beta.git" - that fails, I have to push to the directory name. I am worried that this is part of the problem, but I don't know what I did wrong here.)
So, if the answer to Question 1 is that my method is fine, Question Part 2: what's wrong with what I'm actually doing? If there are hooks I should be using, can someone point me to them?
(An answer to Question 1 that says "run these seven manual steps" will not be a terribly useful answer, seeing as svn checkout + ln -s are two steps.)
Thanks. I want to get back to writing code.
The article Git push is worse than worsless has an interesting discussion about a similar issue.
One of its solution and conclusion involves:
a bare repository on the production server
a cloned repository with a hook to pull what has been pushed into the bare one
So in your case,
one bare repo on which you can push beta and release branches
two cloned repo 'beta' and 'release' with a hook to pull their respective branches from the bare repo.
In short: one step: git push. No more link to manage (since the directory no longer represent a branch in Git, unlike SVN)
Regarding the hook part, a post-receive hook in the bare repo could be all what you need
See Git Tip: Auto update working tree via post-receive hook
$ cd bare
$ chmod +x .git/hooks/post-receive
with a post-receive hook like
#!/bin/sh
cd ../../beta
env -i git reset --hard
cd ../../release
env -i git reset --hard
Note:
the post-receive hook starts out with the GIT_DIR environment variable set to the repo/.git folder, so no matter what path you 'cd' into it will always try to run any following git commands there.
Fixing this is simply a matter of unsetting the GIT_DIR.
'env -i' does just that: it ignores the inherited environment completely and uses only the supplied variables and values.
The solution is to push to single repository, which would employ update or post-receive hook.
There are a few separate possibilities to create two checkouts, which can be used in hook (on server). Going from most lightweight:
If you don't need for those two checked out directories (checked out versions) to actually be git repositories, you can simply use git-archive to export two snapshots (two branches)
git archive --format=tar --prefix=public_html/ master | (cd /var/www/html && tar xf -)
git archive --format=tar --prefix=beta_public_html/ devel | (cd /var/www/html && tar xf -)
where 'master' and 'devel' are names of branches that you wanted to have checked out. Note that --format=tar is not strictly speaking needed, as tar format is default for "git archive". You might also want to remove old contents ("rm -rf public_html/" before "tar xf -" in first line, joined with "&&", and similarly for the second line).
Alternate way of exporting files would be to use low-level commands "git read-tree" (which writes tree to index) and "git checkout-index" (which copies files from index to working area).
In this solution the repository you push into can (and should) be bare, i.e. without working directory itself.
Another solution would be for the repository you push into to have two working directories, which can be created using git-new-workdir script from contrib/workdir. Each of those working areas would have be a checkout of appropriate branch of this repository.
Then update or post-receive hook would unset GIT_DIR, go to those working areas (public_html and beta_public_html), and do "git reset --hard" there.
In this solution "checkouts" would have some git-related metainfo in them (in hidden .git directory).
Yet another solution would be to have two (additional) slave repositories. Pushing into main (master) repository would then (via hook) either push into those two slave repositories, where their hooks would do "git reset --hard" or equivalent, or go to those two slave repositories and do a "git pull" from master there.
Those two slave repositories would be non-bare, and can be [directly in] public_html and beta_public_html. In this solution "checkouts" would be full-fledged git repositories itself.
You can improve this setup by having those slave repositories to have "alternates" (alternate object database) to point to master repository (i.e. be cloned with "git clone --shared ..."); without this object database in slaves starts hardlinked to master. This of course is possible only if master and slaves are on the same filesystem.
Note this solution allows for master repository to be on different host than slave repositories. (although I guess this is flexibility you don't need).
Finally you can instead of current setup deploy gitweb or some other git web interface (see InterfacesFrontendsAndTools and Gitweb wiki pages for a partial list), so that your users can browse different versions and different branches of your repository at their leisure.
In gitweb (and I guess also in other git web interface) thanks to path_info URL support you can view files in browser, and follow links correctly (if they are local), see e.g. git.html from 'html' branch of git.git repository at repo.or.cz.
P.S. "git push" does not update working directory in remote repository by default, because if somebody is working in the non-bare repository you push into, such sideways push can be very unexpected and lead to loss of work.
I use a post-receive hook like this to publish my website, because Git does not touch the working directory when doing a push. The remote repository is a non-bare repository, i.e. it has a working directory.
if [ -n $GIT_DIR ]; then
# Current dir is "<reporoot>/.git/", but we need to run reset at "<reporoot>/".
# Clearing GIT_DIR is needed, or reset will fail with "fatal: Not a git repository: '.'"
unset GIT_DIR
cd ..
fi
git reset --hard
(BTW, note that I can't seem to push to "myapp-beta.git" - that fails, I have to push to the directory name. I am worried that this is part of the problem, but I don't know what I did wrong here.)
When creating a bare Git repository (git init --bare) which does not have a working directory, it is a convention to name the directory "something.git". When having a non-bare repository, the repository is actually in the ".git" subdirectory, so the full path is "something/.git". It seems that in either case you can leave out the ".git" part and Git will detect it automatically.
I'm not really opposed to the other solutions, but I think there's a less hack'ish "Git way" to do this. Here's what I would do:
On my server, I'd set up a sort of a centralized repository (to be managed by Gitosis or some such thing).
From the client end, I'd constantly pull from the repository, make changes and push back. Branches are ofcourse, managed automatically.
I'd pull the required branch from Gitosis into public_html/ beta_public_html of the server. I'd keep it in sync with Gitosis periodically using a Cron job. If you don't like the Cron job idea, you could always use some sort of a hook + script as the others have pointed out.

Resources