bash-it with powerline prompt theme: What's the meaning of {1} next to the git branch name? - powerline

I'm using bash-it with powerline prompt theme. I noticed {1} next to the Git branch name. What does it mean?

It means you have a stash, i.e. you've used git stash at some point.
You can confirm via:
$ git stash list
Also,
$ git stash show
will give you a dry-run of changes, which can be useful.
I often accumulate stashes over time - I use sublime merge which allows me to directly inspect the contents of the stash, which makes it easy to safely drop them without losing any valuable saved data.
Note: The {1} is not limited to the Powerline theme and would likely show in most themes with a git_scm segment enabled.
Disclaimer: I'm a maintainer for Bash-It and of the Powerline theme specifically.

Related

git: temporarily store current files - and return them

I know git stash, but somehow either I am doing something wrong or my problem is not as common as I think.
Scenario: I am coding, committed and pushed a version, doing further code, then to make a decision I would like to test something. For that, I'd love to save the current local files away and return to that state later on to try another solution. Note: in an intermediate un-committed state. Something one would do normally by zipping the project folder and restoring it later.
git stash for me has the crux, that I cannot tell it to simply re-apply the stashed content, ignore anything else, simply recover what was stashed. With git stash apply --force I get (of course) warnings that files are not committed.
Any help?
Use git checkout instead of git stash apply:
$ git checkout stash -- .
This will restore all the files in the current directory to their stashed version.
If I understand the question correctly you can store all untracked files with git stash --include-untracked (or git stash -u for shorten).
After you finish with the tests just revert the stash with git stash pop.

How do i recover my storyboards after git reset --hard HEAD^?

About a week ago, I was pushing my .gitignore file to my repository and was running into small issues with that, and finally figured it out, but noticed that all my storyboards were in the repository too. In a stroke of genius, I looked into getting them out of there and found out about the above git reset command and just put that into my terminal and patted myself on the back and life went on. I just realized today after installing some cocoapods that all my storyboards I spent weeks working on are gone and put two and two together. I've spent the last hour reading through the similar questions, but haven't found anything after reading for a while and am wondering if any other xcode users have run into the same issue and can help.
I should also add that I had only added the storyboards to the stage and hadn't committed them yet at the time of the reset, so today I was using the git reflog command in hopes that they were in the lost and found. I had read that the garbage collection doesn't happen for a month so I don't think (I hope) they're just gone
I downloaded the AWS SDK today and that's all the git reflog command seems to be showing at the moment. Do I need to roll back the git rest HEAD{} command further?
Thank you very much!
You note in a comment that you did a git stash
This is a crucial bit of information, which changes everything. Fortunately, it also makes recovering much easier. In particular it means that your missing files are not "dangling blobs" and do have their original names saved. (Note, by the way, that git stash means git stash save; I'll use the longer form below to distinguish it from other git stash commands.)
The simplest way to recover is to use git stash branch. Pick a new branch name, one that you do not yet have. For illustration I will use saveme, which is a terrible name and you should choose a better one.
git stash branch saveme
This will take your existing git stash, create a new branch using the commit that was current when you ran git stash save. It will then restore your index (staging area) to the way it was at the time you ran git stash save, and restore your work-tree to the way it was at the time you ran git stash save. You can now commit the index:
git commit -m 'save index as a commit'
and then commit the rest of the work-tree if there is anything else to commit:
git add --all
git commit -m 'save everything else as a commit too'
I will add, at the end of this answer (in another edit), a pictorial diagram of what happens with this entire sequence, starting from the first git adds and going through the git stash save and git reset --hard HEAD^ and on to the final git stash branch.
There is one caveat: your index and work-tree must be clean to use git stash branch. If you have uncommitted work, you probably should commit it now, or throw it all out with git reset --hard. Of course, either one has consequences:
If you run another git stash save, the earlier saved stash gets "pushed up" from stash#{0} to stash#{1}. You will then have to use:
git stash branch saveme stash#{1}
to convert that stash to a branch.
If you choose to use git reset --hard, you lose any uncommitted work you have, so be sure that this is OK.
Pictorial diagram
Let's take a look at a hypothetical terminal session, and see what happens with your commits and branches as you work.
$ cd my-git-project
At this point, you are in a Git work-tree. The work-tree is where your files are in their normal form, that the rest of the computer (and you) can work with, instead of their Git-only form, where Git saves every version of every file you or anyone else has ever committed. You are on some branch—let's say master, just for concreteness. This branch has some set of commits, ending in what Git calls the tip commit of that branch. The branch name remembers the hash ID of this tip commit:
...--F--G--H <-- master
Each uppercase letter represents a normal, ordinary commit. (In other words, these stand in for the incomprehensible hash IDs that are the actual names of each commit.) Commit H is the latest one. If your index / staging area and work-tree are "clean", the files in them match those in commit H.
Now you make some changes, and stage some or all of them:
$ ... edit some files ...
$ git add file1 file2 ...
The staging area, aka index, is now not "clean": it no longer matches commit H. Instead, it has copies of the edited and added files.
Your work-tree may or may not match your index. If it does match your index, and if you were to run git commit, Git would make a new commit out of your index (that's what the index / staging-area is for, mainly: to build the next commit), and then your index would match your commit and be clean. If your work-tree matches your index, that too would then be clean. This would look like:
...--F--G--H--I <-- master
where I is the new commit, made from your index.
Instead, though, you ran git stash save. What this does is make two commits, neither of which is on the branch:
...--F--G--H <-- master
|\
i-w <-- stash
The first (lowercase i) commit is the same commit that git commit would have made. It's just not on branch master; it's part of this two-commit "stash bag". The second commit, w, is peculiar: it looks to the rest of Git like a merge commit, but in fact it's just a commit of your work-tree state, even if that's the same as the index state in i.
After making these two stash-bag commits, git stash resets (cleans) your index and work-tree, a la git reset --hard HEAD. So now your index and work-tree match commit H again.
Next, you say you ran git reset --hard HEAD^. This does three things: it resets the index and work-tree state to the state of the selected commit, which is the one just before H; and it makes the name master point to the selected commit as well. So now your repository looks like this:
...--F--G <-- master
\
H [remembered in reflogs, *and* preserved via the stash]
|\
i-w <-- stash
Note that the stash-bag is still there, and still find-able by the name stash. The two stash-bag commits remember commit H by its hash ID. Meanwhile, the name master now remembers the hash ID for commit G instead—and your index and work-tree are "clean", i.e., match that for G.
If you now run git stash branch saveme, this is what Git does in terms of commits:
...--F--G <-- master
\
H <-- saveme
|\
i-w [abandoned]
The index is re-loaded from the i commit, and the work-tree is re-loaded from the w commit. If you now run git commit you get:
...--F--G <-- master
\
H--I <-- saveme
since Git saves the index as a new commit I. The work-tree remains unchanged; if it's clean with respect to I, it's now all clean, and if not, you can git add any remaining changes and commit them:
...--F--G <-- master
\
H--I--J <-- saveme
and now everything is saved permanently (or until you delete the saveme branch) in plain, ordinary commits that you can work with in the usual ways. Note that commit H, which you threw into the recycling bin with git reset --hard HEAD^, has come back on the new branch.
Original answer
I should also add that I had only added the storyboards to the stage and hadn't committed them yet at the time of the reset ...
This makes things harder, because:
... so today I was using the git reflog command
git reflog looks only at abandoned commits.
... in hopes that they were in the lost and found.
They may still be! The "lost and found" is separate from the reflogs.
I had read that the garbage collection doesn't happen for a month so I don't think (I hope) they're just gone
The 30-day grace period is specifically for commit objects that are remembered in reflogs, which these are not. However, all objects get a 14-day grace period. The clock starts at the time you git add the file to the staging area. (Even once the clock runs out, it takes a later git gc --auto to make the files go away, but it's hard to know when that will happen.)
Actually finding your files is a bit trickier. Run:
git fsck --lost-found
which, as the documentation says:
--lost-found
Write dangling objects into .git/lost-found/commit/ or
.git/lost-found/other/, depending on type. If the object is a blob,
the contents are written into the file, rather than its object
name.
Since you did git add these files, and they presumably never were in any commit, they will be "dangling" objects of type "blob". The git fsck command will print a bunch of incomprehensible hash names. You can then change into the .git/lost-found/other/ directory and examine all the files there, which all have these hash names. In amongst all these files, the contents you git added will appear.
For each such file, figure out whether it should be saved away under which sensible file name, and move the file out of the lost-found/other area to one of that name, and you have that file back.

git-tfs clone and cleanup

I have cloned my TFVC from VSTS and it pulled all my branches without any errors. I then followed a number of online posts that said to cleanup my projects by doing the following:
Remove the GlobalSection(TeamFundationVersionControl) section from solution files
remove all *.vssscc files
Remove all *.vspscc files
When I do this I get almost all of my files showing up in the Changes window under Team Explorer. All of these files have no changes when doing a diff except for the files discussed earlier.
What is the proper way to cleanup branches after doing the clone from TFVC to git?
Thanks
If you want to migrate an existing TFVC repos to Git repos, you can use the git-tfs tool, which allows you to migrate a TFVC repo to a Git repo in just a couple of commands.
In my example, with the commands below, I have successfully migrated an existing TFVC repo to Git repo with all branches.
If you don't want to clone the branches, you can specify --branches=VALUE (VALUE=none|auto|all), check https://github.com/git-tfs/git-tfs/blob/master/doc/commands/clone.md
When I do this I get almost all of my files showing up in the Changes window under Team Explorer. All of these files have no changes when doing a diff
That should be due to a bad end of line setting...
except for the files discussed earlier.
First commit them...
Then fix your setting.
You've got 2 options (not mutualy exclusive, you could do the 2. But if you do only one, do the 2nd) :
(old style), set the git core.autocrlf setting. On windows, that's either true to convert all file to a windows eol style or false to tell git to not touch the files. It's a matter of choice. This settings will be used for ALL your repositories but will be personal
(new one recommended) Add a .gitattributes files to telle git how to handle eol for all type of files. This settings will be used for this repository only but will be shared by all the developpers and noone won't be able to commit bad files.
Be aware that for all the strategies that you will try, to be sure that it works, you will have to do soemthing special. You will have to wipe all the files and checkout them all from the repository (because that's at this special moment that git modify the files):
git checkout .
There is a possibility that in fact, the files are modified because they have been checkouted in the format you wish, so commmit them all (you will be obliged) and apply the eol strategy, just after...
A good doc on the subject that you should read carefully and understand before trying something...
PS: handling end of line is not an easy task in a git repository and it will take you quite some time and you will have to try a lot of things before really understanding how it works ( I'm not pretty sure myself ;) )

How to show git diff in Jenkins

I have a build job in Jenkins, which is based on a git project.
Looking at the changes page for each build, I can see the commits that are new to this version, who contributed them, and the list of files modified.
What I'm missing is the option to see the actual diff - what lines of code were changed.
How can this be achieved?
I'm using a local git repo hosted on the same PC as the jenkins server
You can use Last Changes Plugin to accomplish that.
Just install it and make sure to choose from Post-build Actions drop down menu the option Publish Last Changes.

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