func GetRemoteURL(repoDir, remoteName string) (url string, err error) {
	if len(remoteName) == 0 {
		remoteName = _defRemoteName
	}
	gitConfig := filepath.Join(repoDir, ".git", "config")
	gitIni, err := ini.Open(gitConfig)
	if err != nil {
		err = fmt.Errorf("GetRemote: %s", err)
		return
	}
	url, ok := gitIni.Get("remote", remoteName, "url", "")
	if !ok {
		err = fmt.Errorf("GetRemote: Empty or invalid remote name")
	}
	return
}
GetRemoteURL return remote URL or error if repository is not git or url is
empty.
If remoteName is empty, it will be set to default ("origin").
package git
import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"github.com/shuLhan/share/lib/debug"
	"github.com/shuLhan/share/lib/ini"
)
const (
	_defRemoteName = "origin"
	_defRef        = "origin/master"
	_defBranch     = "master"
)
var (
	_stdout = os.Stdout
	_stderr = os.Stderr
)
func CheckoutRevision(repoDir, remoteName, branch, revision string) error {
	if len(remoteName) == 0 {
		remoteName = _defRemoteName
	}
	if len(branch) == 0 {
		branch = _defBranch
	}
	if len(revision) == 0 {
		return nil
	}
	ref := remoteName + "/" + branch
	cmd := exec.Command("git")
	cmd.Args = append(cmd.Args, "clean", "-qdff")
	cmd.Dir = repoDir
	cmd.Stdout = _stdout
	cmd.Stderr = _stderr
	if debug.Value >= 1 {
		fmt.Printf("= CheckoutRevision %s %s\n", cmd.Dir, cmd.Args)
	}
	err := cmd.Run()
	if err != nil {
		err = fmt.Errorf("CheckoutRevision: %s", err)
		return err
	}
	cmd = exec.Command("git", "checkout")
	if debug.Value == 0 {
		cmd.Args = append(cmd.Args, "--quiet")
	}
	cmd.Args = append(cmd.Args, "--track", ref, "-B", branch)
	cmd.Dir = repoDir
	cmd.Stdout = _stdout
	cmd.Stderr = _stderr
	if debug.Value >= 1 {
		fmt.Printf("= CheckoutRevision %s %s\n", cmd.Dir, cmd.Args)
	}
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("CheckoutRevision: %s", err)
		return err
	}
	cmd = exec.Command("git", "reset")
	if debug.Value == 0 {
		cmd.Args = append(cmd.Args, "--quiet")
	}
	cmd.Args = append(cmd.Args, "--hard", revision)
	cmd.Dir = repoDir
	cmd.Stdout = _stdout
	cmd.Stderr = _stderr
	if debug.Value >= 1 {
		fmt.Printf("= CheckoutRevision %s %s\n", cmd.Dir, cmd.Args)
	}
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("CheckoutRevision: %s", err)
	}
	return err
}
func Clone(remoteURL, dest string) (err error) {
	err = os.MkdirAll(dest, 0700)
	if err != nil {
		err = fmt.Errorf("Clone: %s", err)
		return
	}
	cmd := exec.Command("git", "clone")
	if debug.Value == 0 {
		cmd.Args = append(cmd.Args, "--quiet")
	}
	cmd.Args = append(cmd.Args, remoteURL, ".")
	cmd.Dir = dest
	cmd.Stdout = _stdout
	cmd.Stderr = _stderr
	if debug.Value >= 1 {
		fmt.Printf("= Clone %s %s %s\n", remoteURL, cmd.Dir, cmd.Args)
	}
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("Clone: %s", err)
	}
	return
}
func FetchAll(repoDir string) (err error) {
	cmd := exec.Command("git", "fetch")
	if debug.Value == 0 {
		cmd.Args = append(cmd.Args, "--quiet")
	}
	cmd.Args = append(cmd.Args, "--all", "--tags", "--force")
	cmd.Dir = repoDir
	cmd.Stdout = _stdout
	cmd.Stderr = _stderr
	if debug.Value >= 1 {
		fmt.Printf("= FetchAll %s %s\n", cmd.Dir, cmd.Args)
	}
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("FetchAll: %s", err)
	}
	return
}
func FetchTags(repoDir string) error {
	cmd := exec.Command("git", "fetch")
	if debug.Value == 0 {
		cmd.Args = append(cmd.Args, "--quiet")
	}
	cmd.Args = append(cmd.Args, "--tags", "--force")
	cmd.Dir = repoDir
	cmd.Stdout = _stdout
	cmd.Stderr = _stderr
	if debug.Value >= 1 {
		fmt.Printf("= FetchTags %s %s\n", cmd.Dir, cmd.Args)
	}
	err := cmd.Run()
	if err != nil {
		err = fmt.Errorf("FetchTags: %s", err)
	}
	return err
}