Gist is a modern pastebin service operated by GitHub. Unlike a simple pastebin site, a gist behind the scenes is using the Distributed Version Control System (DVCS) Git. “All gists are Git repositories, so they are automatically versioned, forkable and usable from Git.”
When including source code on a site there are scripts that allow one to include the code from the gist site. Anyone interested in the source has a cleaner interface to view, copy, download, or fork.
An example is on one of my blog posts. To show the source on the page took only one line:
[gist id=”6680049″ file=”Gather.groovy”]
This depends on the gist support you have on your blog system. WordPress, for example, supports gist embedding by use of ‘shortcodes‘.
Yes, this is old news, but I had this post in draft mode, so I may as well post it.
The various cloud sync services provide a good way to backup or remote a Git repository for ‘single developer’ situations. The main advantages are that the cost is minimal and no ‘server’ is required. In this post we use something quite different, the new BitTorrent Sync (BTSync) system.
BTSync is a serverless folder syncing system. Instead of using a remote server storage system, it creates a fast private peer-to-peer file sync system using a P2P protocol. Note it is not necessarily a replacement for a server, backup system, or even other services such as DropBox, more like a welcome addition that covers some limits that others may have, such as file size limitations, speed, and privacy.
Using this type of service is very easy. I took the easy way out and “forked” a very well written blog post by Sergei Shvetsov that did the same thing, only using DropBox. Using Git with Dropbox. In this post, however, I use BTSync and I am running on Windows (most blogs show examples on *nix). Of course, experienced Git users may approach this very differently. The following uses a console shell UI.
Process
1. Create a local repo
2. Create a “bare” repo that lives in the Synced folders
3. Add the bare repo as the origin of the local repo.
Result
Now on another system, the synced folder, which contains the bare repo is available as if it was created locally. During development or other uses, since we are using the working repo and only occasionally the ‘bare’ or origin repo in the synced folder, the synced folder is not constantly transferring data over the network to any other synced locations (there can be many).
This approach is diagrammed below. (On mobile device this ASCII diagram using <PRE> tag looks horrible.) Two systems with the two Git repos:
Alternatives
Of course whenever possible direct access to remote repos from a clone is preferred, or via a server. For private use and 5 users, Bitbucket offers free code repositories.
Example
Below is a walkthrough of this process using a Windows cmd shell.
C:\temp\git-on-BTSync\new-project>git push -u dropbox master
Counting objects: 3, done.
Writing objects: 100% (3/3), 223 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To C:\Users\jbetancourt\BTSync\git\new-project.git
* [new branch] master -> master
Branch master set up to track remote branch master from dropbox.
Use another system
On another system that is running BTSync, like a laptop, the bare repository folder is already synced. Now we can clone the repo.
cd \temp
mkdir remote-workspace
cd remote-workspace
git clone -o dropbox \Users\jbetancourt\BTSync\git\new-project.git
Cloning into 'new-project' ...
done.
cd new-project
dir
11/29/2013 10:48 AM 5 README.txt
Now make some changes
On the laptop we modify a file and commit it.
BitTorrentSync has been updated and now the process of syncing folders is either easier or harder, depending on you viewpoint. There are also some limitation for the free product, like ten folder limit.
The machine having a source sync must be on to allow syncing, of course. Not true with a server based sync solution like Dropbox. This is only required while the local and remote folders are syncing of course. In many BTSync articles and blog posts the wrong impression is given that this is a continuous requirement. In fact, as soon as you see the sync complete, if you have the BTSync app visible you can shut down the source machine.
Damage is also synced: If one of the synced repos gets damaged, that damage is reproduced in all correlated syncs. This can be prevented by using BTsync’s read only share feature. This would introduce some limitations or other complexities.
Repository ignored files are synced
There was a discussion on whether the .git folder should be synced. Not sure I follow the rational.
I don’t know if there are any issues with BitTorrent Sync for long term work with a Git repo. People have complained of such issues with Dropbox. See the link for Mercurial use on DropBox below. In the comments of that blog post, robhamilton posts: “… found that it would break the Mercurial repo. Mercurial locks files and creates temp journal files which get sync’d by the dropbox daemon. My advice is to stop dropbox, perform your push/commit, then restart dropbox. Pulls and clones are readonly.” Is this an issue with Git? I don’t think so since we are using the bare repo approach.
Updates
Mobile Git
Dec 24, 2013: I did not investigate the mobile Git use with BTSync as shown above. BTSync has a mobile app that allows the sync to mobile devices. On that device a mobile Git client can access the synced bare repo to clone into a mobile local repo. There are now a few mobile Git clients, for example, SGit.
The Ant Hook scripts using Groovy implementation is extended with the ability to also skip target execution. Thus, an “around” advice AOP like or filter.
In the last post, Ant Hooks using Groovy Script via Scriptdef, we used the Ant BuildListener interface to add a hooks feature that invokes a Groovy script mapped to build events. Now we implement a true “around advice”. Admittingly kludgy, but ….
Approach
Since the hook script has the Ant Event object, we have access to the Target object currently about to be executed. Target has a convenient method to allow target skip:
public void setUnless(java.lang.String property):
Sets the "unless" condition to test on execution.
if the property is set, the task will not execute.
Demo
The demo Ant build script is modified with two new targets, ‘deploy’ and ‘build’. Also, the default target is changed to ‘build’.
Listener implementation
The actual listener is slightly modified to test for the skip property. If found the ‘unLess’ method is used on the target and the target is skipped.
/**
* Ant build listener that invokes groovy hook scripts.
*
* @author josef betancourt
*
*/
class HookListener implements SubBuildListener {
...... see prior post ......
/** Invoke the 'started' or 'finished' root or target hook script */
def evokeTargetHook(BuildEvent event, When when){
def b = new Binding()
b.event=event
b.hook=this
def shell = new GroovyShell(b)
def hookName = "${event.target.name}_${TARGETHOOK}${when.name}"
def hooked = false
def stored = projectHooks[hookName]
if(stored){
hooked = true
shell.evaluate(stored)
}else{
def hook = rootHooks[hookName]
if(hook){
hooked = true
shell.evaluate(hook)
}
}
if( hooked && (when == When.STARTED) ){
def skipSet = event.project.getProperty(
"${event.target.name}_skipTarget")
if(skipSet){
event.project.setProperty(skipSet, "true")
event.target.setUnless(skipSet)
}
}
}
/** invoked from a hook script */
static void skipTarget(BuildEvent event) {
def name = event.target.name
def project = event.project
project.setProperty(name + "_skipTarget", 'set')
}
...... see prior post ......
}
...... see prior post ......
Many version control systems use ignore files in a folder to indicate resources that should not be tracked , the target ignored files. These ignore files could be in any folder in the project where something must be ignored, natch.
These ignore files are a separate concern, not germane to the purpose of the source code. Should we also have files that indicate how to compile? Compile and config concerns are localized, either in the build scripts or in other types of management system. Likewise, the version control metadata should also be separate from the source.
This is comparable to how in the past Subversion version control system had .svn files throughout a project’s source folders. These were used as part of their vcs “bookkeeping”. Currently the “bookkeeping” was centralized into one .svn file at the project’s root folder, like found in Git. (Not an SVN expert so this is just what I see when I use SVN).
A few that use ignore files all over the place are: Git, Mercurial, CVS, and Subversion. Yes, Subversion too, except that it hides these in this nebulous ‘properties’ objects that are not seen but can cause great pain.
Any issues?
Other than be a context leak, any issues? None directly. Yet, if you search the web, there are many pleas for making automation tools and apps work around the inclusion of these files. Extra steps must be taken to remove from views in IDE or in searches. And so forth.
What should be done?
Ignore files or properties should be handled just like everything else. They should be localized in the version control system’s metadata folder (db or workspace).
For example, with Git, the .git repository could have a folder called “ignores”:
./.git/hooks
./.git/ignores
./.git/refs
...
Cons
There are probably many reasons for the current approach: performance, simplicity, etc. WTHDIK
On a StackOverflow question asking about example source code, one answer pointed to a very good resource: jgit-cookbook.
JGit is a lightweight pure Java library implementing the Git version control system. It is used by the EGit team provider in Eclipse among other places.
Finally more tools are starting to use this convention. I first saw its use in the Ant build framework. I even mentioned it to some Linux nerd on how to improve his utility and got an angry rebuff. Oh well.
* The patterns in .gitignore and .gitattributes files can have **/, as a pattern that matches 0 or more levels of subdirectory. E.g. “foo/**/bar” matches “bar” in “foo” itself or in a subdirectory of “foo”.
In a git repository created using the –separate-git-dir option executing “git status” is not showing any changes.
In a git repository created using the –separate-git-dir option executing “git status” is not showing any changes. This was working correctly for weeks.
Details
I created a new file in the top level folder, it doesn’t show as untracked. Tried “git status -u -v”. Nothing. Removed the .gitignore file. Nothing. Strange.
The separate directory is on a shared drive in Windows with a connected drive “k:”.
“git fsck” shows no issue, etc.
Work around
Anyway, what I did. I deleted the .git file. Then I reinited:
git init –separate-git-dir K:/where/it/is/at.git
Now it works.
Details
OS: Windows 7, 64bit.
Git: 1.7.9.msysgit.0
As some light research I was looking at how to access a Git repository’s current branch name in a Groovy script. Could use a process invocation or a library like JGit
As some light research I was looking at how to determine a Git repository’s current branch name in a Groovy script.
This would be run as:
groovy test\Git.groovy temp\git\SdWf\depot\project.git
refs/heads/master
One problem with the JGit approach is that, afaik, this won’t work if the repo is represented by a ‘pointer’ file, i.e., created with the –separate-git-dir option. Also, unlike the Git branch command, you must open the target git repo at it’s root level, not a nested subdirectory of the repo.
Environment
— Windows 7 64bit Professional
— git version 1.7.6.msysgit.0
— Groovy Version: 1.8.2 JVM: 1.6.0_25
I give an example of the simple workflow I’m currently using in a single developer single location Git workflow.
I’m finding Git to be very useful. Since I use it in conjunction with the “official” VCS at my job, I classify this as a SDGWF situation. Below I give an example of the simple workflow I’m currently experimenting with. The following is based on a Windows development workstation. Usually any blog posts involving Git are *nix based.
Note that the first repository created is “bare“, i.e., it does not have any work files. It is not created in the project work folder. At the project folder, a new Git repository is created, but with the –separate-git-dir option the first repository is used as the actual project repository.
Instead of a .git subdirectory, a .git file is created at the project folder, and this file points to the actual Git repo.
Why use this setup?
One reason is to allow tools to transparently work with the sanctioned project folder. For example, if we use the ‘normal’ repo setup, to zip the project, one would have to filter out the
.git subfolder (which could get large). Another reason is to allow backups of the working repo; one can delete a project and inadvertently delete the local repo. The last two reasons could be avoided by not creating the local repo within the project folder, of course.
Usage examples
Next day we are assigned some tasks at work. For this example, we’ll make up a naming approach:
defect: dNNNNN-name
feature: fNNNNN-name
Also, for this example, we’ll just have two defects and one feature:
d12345-validation-fails
d54321-login-box
f52123-error-report
Rather then waiting to create the branches when the branch is needed, we just create them now:
C:\temp\git\SdWf\project>git checkout d54321-login-box
Switched to branch 'd54321-login-box'
C:\temp\git\SdWf\project>git merge master
Already up-to-date.
C:\temp\git\SdWf\project>echo Have to go. >> hello.txt
C:\temp\git\SdWf\project>git commit -a -m "made some fixes"
[d54321-login-box db17a9e] made some fixes
1 files changed, 1 insertions(+), 0 deletions(-)
C:\temp\git\SdWf\project>git diff master
diff --git a/hello.txt b/hello.txt
index d4f3cf2..7fe577f 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
hello world!
+Have to go. ^M
Now lets switch to the feature branch …
C:\temp\git\SdWf\project>git checkout f52123-error-report
Switched to branch 'f52123-error-report'
C:\temp\git\SdWf\project>git merge master
Already up-to-date.
C:\temp\git\SdWf\project>echo Created new feature >> hello.txt
C:\temp\git\SdWf\project>git diff master
diff --git a/hello.txt b/hello.txt
index d4f3cf2..17244a7 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
hello world!
+Created new feature ^M
C:\temp\git\SdWf\project>git commit -a -m "finished the feature"
[f52123-error-report aef7f49] finished the feature
1 files changed, 1 insertions(+), 0 deletions(-)
C:\temp\git\SdWf\project>git log --graph
* commit e935e0220ab90945f6160db00eee6bfd13173b6d
Author: josef betancourt
Date: Mon Oct 3 19:07:29 2011 -0400
initial commit
Lets log all the branches ….
C:\temp\git\SdWf\project>git log --graph --branches
* commit aef7f4990b63dbb8da4f81558ac492609afa3522
| Author: josef betancourt
| Date: Mon Oct 3 19:33:09 2011 -0400
|
| finished the feature
|
| * commit db17a9eb9e0672b0e6d2b9a9bef645a5d3a6e1de
|/ Author: josef betancourt
| Date: Mon Oct 3 19:29:41 2011 -0400
|
| made some fixes
|
| * commit 0aa5930c88d619b58ce14908ba8795736988d46c
|/ Author: josef betancourt
| Date: Mon Oct 3 19:26:05 2011 -0400
|
| worked on defect
|
* commit e935e0220ab90945f6160db00eee6bfd13173b6d
Author: josef betancourt
Date: Mon Oct 3 19:07:29 2011 -0400
initial commit
Show the detailed branch structure …
C:\temp\git\SdWf\project>git show-branch
! [d12345-validation-fails] worked on defect
! [d54321-login-box] made some fixes
! [f52123-error-report] finished the feature
* [master] initial commit
----
+ [f52123-error-report] finished the feature
+ [d54321-login-box] made some fixes
+ [d12345-validation-fails] worked on defect
+++* [master] initial commit
Now check out master branch and merge the first defect …
git checkout master
C:\temp\git\SdWf\project>git merge --no-ff d12345-validation-fails
Merge made by recursive.
hello.txt | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
C:\temp\git\SdWf\project>git merge --no-ff d54321-login-box
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
Edit the file and accept the changes, then merge …
C:\temp\git\SdWf\project>type hello.txt
initial hello
hello world!
Have to go.
C:\temp\git\SdWf\project>git status
# On branch master
# Unmerged paths:
# (use "git add/rm ..." as appropriate to mark resolution)
#
# both modified: hello.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
C:\temp\git\SdWf\project>git commit -a -m "merged in 2nd defect"
[master cc7ebf6] merged in 2nd defect
Now merge the feature branch into master …
C:\temp\git\SdWf\project>git merge --no-ff f52123-error-report
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
C:\temp\git\SdWf\project>type hello.txt
initial hello
hello world!
<<<<<<>>>>>> f52123-error-report
Edit the file, then commit the merge …
C:\temp\git\SdWf\project>npp hello.txt
C:\temp\git\SdWf\project>"C:Program Files (x86)Notepad++notepad++.exe" hello.txt
C:\temp\git\SdWf\project>type hello.txt
initial hello
hello world!
Have to go.
Created new feature
C:\temp\git\SdWf\project>git commit -a -m "merged in feature"
[master dc58815] merged in feature
Show the final results using a log with graphics ….
* commit dc58815ae250ee089e9e83db3b6e301a5a4552a9
| Merge: cc7ebf6 aef7f49
| | Author: josef betancourt
| | Date: Mon Oct 3 19:57:14 2011 -0400
| |
| | merged in feature
| |
| * commit aef7f4990b63dbb8da4f81558ac492609afa3522
| | Author: josef betancourt
| | Date: Mon Oct 3 19:33:09 2011 -0400
| |
| | finished the feature
| |
* | commit cc7ebf6c79fc0abb82b2b0d1fd5e53bcbf4fb94c
| Merge: 8e47975 db17a9e
| | | Author: josef betancourt
| | | Date: Mon Oct 3 19:55:25 2011 -0400
| | |
| | | merged in 2nd defect
| | |
| * | commit db17a9eb9e0672b0e6d2b9a9bef645a5d3a6e1de
| |/ Author: josef betancourt
| | Date: Mon Oct 3 19:29:41 2011 -0400
| |
| | made some fixes
| |
* | commit 8e479756f7db2b926259c9774d5fd8cb38d14935
| Merge: e935e02 0aa5930
| |/ Author: josef betancourt
|/| Date: Mon Oct 3 19:51:30 2011 -0400
| |
| | Merge branch 'd12345-validation-fails'
| |
| * commit 0aa5930c88d619b58ce14908ba8795736988d46c
|/ Author: josef betancourt
| Date: Mon Oct 3 19:26:05 2011 -0400
|
| worked on defect
|
* commit e935e0220ab90945f6160db00eee6bfd13173b6d
Author: josef betancourt
Date: Mon Oct 3 19:07:29 2011 -0400
initial commit
That’s a simple example. I’m sure I missed some steps during the text captures.
Currently I’m just using the “master” branch as the development branch. I only use branches for short term coding. I may go back to using more branches as I get better with Git.
Windows Explorer started hanging when using copy & paste of folders. I noticed that it only involved folders that had a “.git” subfolder.
Windows Explorer started hanging when using copy & paste of folders. I noticed that it only involved folders that had a “.git” subfolder.
Symptoms
Copy a folder and explorer does not refresh; you have to hit F5.
After the manual refresh, click on a folder and the explorer gets an hour glass.
The explorer.exe CPU usage reaches 50% and higher.
Only happens when a subfolder was named “.git”.
.git folder could even be empty.
Easy approach unsuccessful
I uninstalled Git and TortoiseGit then restarted the system. Still happening. Hmmm, that should have removed everything. Nope, I looked in the Registry and TortiseGit was still hanging around. I removed all traces and then even used ShellExView tool and could not find any shell extension that could be doing this. Using that tool I disabled all non-Windows shell extensions. Still happening.
More tools to help
This happened a month ago so I don’t remember all the steps I took. I used some of the SysInternals tools but they didn’t help much; you need a lot of internal Windows details to really use some of them.
However, I think it was using the Process Manager and looking only at file activity that all the info finally gave me a clue.
Progress
5:23:14.4666723 PM explorer.exe 5096 ReadFile C:Documents and Settingst16205Start MenuLocal Disk (C)target.lnk SUCCESS Offset: 0, Length: 299
5:23:14.4668257 PM explorer.exe 5096 QueryInformationVolume C:Documents and Settingst16205Start MenuLocal Disk (C)target.lnk SUCCESS VolumeCreationTime: 9/15/2009 8:47:39 AM, VolumeSerialNumber: 64B6-6315, SupportsObjects: True, VolumeLabel:
It seemed to be hanging at that point!
Solution
I looked in the Windows Start Menu list and saw that I had placed a link of the C: drive there. Not a junction or anything fancy, just a drag and drop of a shortcut (I think). I removed that link and the problem was solved.
Back to Git
Reinstalled Git and all is fine, knock on wood.
No explanation yet
Not really debugging, just floundering with a purpose. But, why would this only effect folders named “.git”, when even Git is not even installed. Strange.