Git Tips And Workflows, Round 2: basics, stashes and other bits
You’d think I fired all my bullets with my previous round of curated tips, but no, I have plenty more.
The new year has just kicked off and I am happy to be back with more findings, shortcuts and workflows to enhance your git experience. I also humbly anticipate the optimizations and corrections that you guys will feed me back. I very much appreciate that.
Before I dive in the next round let me also give you a second to open a tab for my older post on more advanced git aliases, if you haven’t seen it already.
Ready? Alright here we go, starting from the simple things this post will cover:
Table Of Contents
- Find the root of the project
- Delete a remote branch
- Add all unknown files to a repository while honoring .gitignore
- Show all the content in your stashes
- Track all remote branches as local branches
- Git cherry to see which commits have been merged to a branch
- Check deleted files consistency between branches
- Bonus Tips On Submodules
Find the root of the project
Say your build script needs to know the root of your git repository. Here
rev-parse
to the rescue:
git rev-parse --show-toplevel
Which results in:
To automatically cd
into it you can of course type:
cd $(git rev-parse --show-toplevel)
Delete a remote branch
This used to be more obscure before git v1.7.0
. Now they improved the UI and
it’s fairly straightforward:
git push origin --delete <branchName>
Easy enough. (Stack Overflow reference)
Add all unknown files to a repository while honoring .gitignore
Yes yes, we’ve all done git add *
to add everything that is unknown to the
index and the next commit. This works well until you have a well crafted
.gitignore
for your project. At that point git will halt and show you the
following warning:
And yes you can force the issue with the -f
flag, but then you lose the
benefit of having a .gitignore
file in the first place and you will add files
that you don’t want to track.
So here’s how you add to your repository all unknown files, but respecting the
.gitignore
and not raising any alarms (Update: Helpful readers have have
pointed out a much simpler way in the comments, which I report here):
git add '*'
Or simply:
git add -A
Previously I had done it like this:
git ls-files --other --exclude-standard | xargs git add
Which results in the right files being properly added:
st
is my alias for git status
.
Show all the content in your stashes
I use the git stash
command a lot in different situations. It is a very
convenient way to temporarily save work which either is transient, or
incomplete and thus should not be committed. For example I might use a stash to
save a work in progress when I have to switch to the production branch to
resolve a blocker. Or to reapply a temporary change I need often, but can’t
commit.
If you use stashes a lot, you might have hard time remembering what’s in them, whether you have named them properly or not.
So you you type git stash list
, and for example you get this output:
What was in stash@{2}
again? Or even better: where did I
save that fix I was working on last Thursday?
So the following one-liner shows you the diff
content of all your stashes. I
found it quite useful (I indent it for readability but it can all go on one
line or in one bash function):
for stash in $(git stash list | awk '{print $1}' | sed -e 's/://'); do
(echo $stash && git stash show -p $stash);
done
The result will allow you to see the contents of all your stashes:
Track all remote branches as local branches in a project
It is not uncommon that you want to track all the remote branches of a project with local branches. I had this need several times. So I found this short command on - surprise - Stack Overflow:
for remote in $(git branch -r | grep -v master); do
git checkout --track $remote ;
done
It will create all the local branches needed and make sure they are tracking the remote ones.
Git cherry to see which commits have been merged to a branch
During the past year I worked with a huge Subversion repository for which I
acted as Branch/Integration Manager. Obviously I used the fantastic bridge
git svn
for the task - for which I wrote a well received post last
year. It worked wonders and accelerated my work a great deal.
A slight annoyance was that sometimes I had to resort on manipulating and cherry-picking single commits between branches.
One command I found useful is the lesser known git cherry
(man page),
which given two branches lists which commits have not been merged upstream.
Here for example how you list commits present in master
but not present in
develop
branch:
git cherry -v --abbrev develop master
For example check out the output:
The interesting feature of the cherry
command is that
git cherry
compares the changeset rather than the commit id (sha1), you can usegit cherry
to find out if a commit you made locally has been appliedupstream
under a different commit id.
Check deleted files consistency between branches
As mentioned above, for a while I worked in an environment where everyone used Subversion but me. This created some interesting challenges and my normal git superowers sometimes had to be enhanced by random Unix cleverness.
One time I had to do a thorough consistency check to make sure all files that had been deleted in the master branch, had also been deleted in the release branch. Here’s how I did it.
First I collected all the delete actions in master:
git checkout master
git log --all --pretty=format: --name-only --diff-filter=D | sort -u > deleted.txt
Then I verified that those delete actions really corresponded to deleted files (some files might have been re-added later):
for f in $(cat deleted.txt); do if [ ! -f $f ]; then echo $f; fi done > really-deleted.txt
And then I listed files that existed in the release-branch
while they were
gone in master
:
git checkout release-branch
for f in $(cat really-deleted.txt); do if [ -f $f ]; then echo $f; fi done > problem.txt
The file problem.txt
contained the files that were not deleted.
Bonus Tips On Submodules
As an extra bonus for you dear reader I want to point you to my latest post on useful workflow and tips for git submodules on Atlassian’s Blog. Those are things you will run into if you ever work with them at all.
Conclusion
This ends the second round of my accumulated tips. I have a few more in store. If you’d like to be notified of my next posts you can Follow @durdn or sign up to be notified by email below.