Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/git fork #628

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ install:
if grep "$(COMMAND)" need_git_commit >/dev/null; then \
cat ./helper/has-git-commit >> $(TEMPFILE); \
fi; \
if grep "# needed_by: $(COMMAND)" helper/config-value >/dev/null; then \
cat ./helper/config-value | grep -v "# needed_by:" >> $(TEMPFILE); \
fi; \
tail -n +2 bin/$(COMMAND) >> $(TEMPFILE); \
cp -f $(TEMPFILE) $(DESTDIR)$(BINPREFIX)/$(COMMAND); \
fi; \
Expand Down
110 changes: 82 additions & 28 deletions bin/git-fork
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,75 @@ test -z "$url" && url=$(git remote get-url origin 2> /dev/null) && origin=true
# validate repo url
test -z "$url" && abort "github repo needs to be specified as an argument"

# validate user
echo "Enter your github username"
read user
[ -n "$user" ] || abort "git username required"
echo "Enter github two-factor authentication code (leave blank if not set up)"
read MFA_CODE

# extract owner + project from repo url
project=${url##*/}
owner=${url%/$project}
project=${project%.git}
if [[ $owner == git@* ]]; then
owner=${owner##*:}
else
owner=${owner##*/}
fi
owner=${owner##*[/:]}
# Yes, the following extracts server for both SSH and https references
server=${url##*@}
server=${server##*://}
server=${server%%[/:]*}

# validate
[ -z "$project" -o -z "$owner" ] && abort "github repo needs to be specified as an argument"

# determine github credentials
user=$(get_config_value "$server.user")
token=$(get_config_value "$server.token")
if [[ $(get_config_value "$server.add-api") == "true" ]]; then
api_server="api.$server"
else
api_server=$server
fi
# retrieve the API prefix and clean it up (i.e. "api/v3/")
api_prefix="$(get_config_value "$server.api-prefix")/"
api_prefix=${api_prefix#/}
api_prefix=${api_prefix/%\/\//\/}

if [[ -z "$user" ]]; then
# validate user
echo "Enter your github username"
read user
[ -n "$user" ] || abort "git username required"
fi

if [[ -z "$token" ]]; then
echo "Enter github two-factor authentication code (leave blank if not set up)"
read MFA_CODE
fi

auth_info=''
header_info=''
if [[ -n "$token" ]]; then
header_info="-H \"Authorization: token ${token}\""
elif [[ -n "$MFA_CODE" ]]; then
auth_info="-u \"$user\""
header_info="-H \"X-GitHub-OTP: $MFA_CODE\""
elif [[ -n "$password" ]]; then
auth_info="-u \"$user\""
else
echo "No login credentials specified."
exit 1
fi

# create fork
curl -qs \
-X POST \
-u "$user" \
-H "X-GitHub-OTP: $MFA_CODE" \
"https://api.github.com/repos/$owner/$project/forks"
IFS="'" cmd="curl -qs -X POST $auth_info $header_info https://$api_server/${api_prefix}repos/$owner/$project/forks"
eval $cmd | grep "message" >/dev/null

[ $? = 0 ] || abort "fork failed"
[ $? = 0 ] && abort "fork failed"

use_ssh=$(get_config_value "$server.use-ssh")
if [[ -z "$use_ssh" ]]; then
echo "Add GitHub remote branch via SSH (you will be prompted to verify the server's credentials)? (y/n)"
read use_ssh
fi

echo "Add GitHub remote branch via SSH (you will be prompted to verify the server's credentials)? (y/n)"
read use_ssh
# Check if user has ssh configured with GitHub
if [ -n "$use_ssh" ] && ssh -T git@github.com 2>&1 | grep -qi 'success'; then
remote_prefix="git@github.com:"
if [ -n "$use_ssh" ] && ssh -T git@$server 2>&1 | grep -qi 'success'; then
remote_prefix="git@$server:"
else
remote_prefix="https://github.com/"
remote_prefix="https://$server/"
fi

if [ "$origin" = true ]; then
Expand All @@ -54,9 +87,30 @@ if [ "$origin" = true ]; then
git fetch origin
else
# clone forked repo into current dir
git clone "${remote_prefix}${user}/${project}.git" "$project"
# add reference to origin fork so can merge in upstream changes
cd "$project"
git remote add upstream "${remote_prefix}${owner}/${project}.git"
git fetch upstream
git clone "${remote_prefix}${user}/${project}.git" "$project" 2>/dev/null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the output of git clone is cumbersome, but still think we should not hide the error message. They are like low level log, which may be useful sometimes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still insist the need for the output of git clone.


# Check to make sure we cloned the repo. Backoff exponetially and try again
timeout=( 2 2 2 6 6 6 20 20 )
total_wait=0
until [[ (( "$total_wait" > 60 )) || -d "$project" ]]; do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it will wait for 64(44 plus the last 20) seconds.

echo "Github is being slow today. Waiting $timeout secs to attempt clone."
sleep ${timeout[0]}
total_wait=$(expr $total_wait + ${timeout[0]})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use total_wait=$((total_wait + timeout[0])), which is more modern.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that, but some of the older shells don't understand the double parenthesis. So I opted for the more traditional form.

# drop the first element and prepare to wait the next time interval
unset timeout[0]
timeout=( ${timeout[@]} )

git clone "${remote_prefix}${user}/${project}.git" "$project" 2>/dev/null
done

if [[ -d "$project" ]]; then
# add reference to origin fork so can merge in upstream changes
cd "$project"
git remote add upstream "${remote_prefix}${owner}/${project}.git" 2>/dev/null
[[ $? > 0 ]] && echo "WARN: upstream reference already exists"
git fetch upstream
else
echo "Github did not fork within 60 seconds or issue cloning repo."
exit 1
fi
fi
11 changes: 11 additions & 0 deletions helper/config-value
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# needed_by: git-fork

get_config_value() {
echo $(git config git-extras.$1)
}

# set_config_value "key" "value" "global|system" (global or system not required)
set_config_value() {
$(git config ${3+--$3} git-extras.$1 $2)
echo $?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, I prefer to use git config ${3+--$3} git-extras.$1 $2 directly.
When writing shell script, people are more relied on $? that the return value to check if the previous command succeeded.

}
69 changes: 68 additions & 1 deletion man/git-fork.1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "GIT\-FORK" "1" "August 2016" "" "Git Extras"
.TH "GIT\-FORK" "1" "February 2017" "" ""
.
.SH "NAME"
\fBgit\-fork\fR \- Fork a repo on github
Expand Down Expand Up @@ -40,7 +40,71 @@ adds the forked repo as a remote called \fBorigin\fR
.P
Remotes will use ssh if you have it configured with GitHub, if not, https will be used\.
.
.P
Your Github settings can now be saved as git config values instead of specifying them each time\. To enable this you need to execute a few git config commands like the following\.
.
.IP "" 4
.
.nf

$ git config \-\-global git\-extras\.github\.com\.user greatcoder99
.
.fi
.
.IP "" 0
.
.P
Assuming that your username is \'greatcoder99\'\. All the configuration values are prefixed with \'git\-extras\.\' followed by server hostname and then finally by the variable name (defined below)\.
.
.P
In addition, other Github instances may be used other than just github\.com\. So if you have a Github Enterprise instance, then using that hostname instead of github\.com will work as expected\.
.
.P
Variables that are currently supported:
.
.IP "" 4
.
.nf

user: The username that the Github instance knows you as

token: The personal access token that has been generated to allow
password\-less access to the API\.

add\-api: In most cases this should be set to true\. This adds the \'api\'
hostname to the repo location (i\.e\. github\.com becomes api\.github\.com)
to access the Github API\. The time you would not set this is when
your API hostname is the same as Github instance hostname\.

api\-prefix: Github Enterprise much of the time uses "/api/v3/" as a
entry point to the API\. Regular Github access does not need to
have a prefix specified\. Consult your Github administrator for
the correct prefix to use\.

use\-ssh: Set to true in order to set the upstream remote reference
to use SSH instead of https\.
.
.fi
.
.IP "" 0
.
.SH "EXAMPLE"
Create settings to prevent answering questions:
.
.IP "" 4
.
.nf

$ git config \-\-global git\-extras\.github\.com\.user bigdog
$ git config \-\-global git\-extras\.github\.com\.token d149feb47\.\.\.\.
$ git config \-\-global git\-extras\.github\.com\.add\-api true
$ git config \-\-global git\-extras\.github\.com\.use\-ssl true
.
.fi
.
.IP "" 0
.
.P
Fork expect\.js:
.
.IP "" 4
Expand Down Expand Up @@ -102,6 +166,9 @@ $ git fork
.SH "AUTHOR"
Written by Andrew Griffiths <\fImail@andrewgriffithsonline\.com\fR>
.
.P
Github Enterprise support and settings by Gerard Hickey <\fIhickey@kinetic\-compute\.com\fR>
.
.SH "REPORTING BUGS"
<\fIhttps://github\.com/tj/git\-extras/issues\fR>
.
Expand Down
52 changes: 49 additions & 3 deletions man/git-fork.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions man/git-fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,49 @@ git-fork(1) -- Fork a repo on github

Remotes will use ssh if you have it configured with GitHub, if not, https will be used.

Your Github settings can now be saved as git config values instead of
specifying them each time. To enable this you need to execute a few git
config commands like the following.

$ git config --global git-extras.github.com.user greatcoder99

Assuming that your username is 'greatcoder99'. All the configuration
values are prefixed with 'git-extras.' followed by server hostname and
then finally by the variable name (defined below).

In addition, other Github instances may be used other than just
github.com. So if you have a Github Enterprise instance, then using that
hostname instead of github.com will work as expected.

Variables that are currently supported:

user: The username that the Github instance knows you as

token: The personal access token that has been generated to allow
password-less access to the API.

add-api: In most cases this should be set to true. This adds the 'api'
hostname to the repo location (i.e. github.com becomes api.github.com)
to access the Github API. The time you would not set this is when
your API hostname is the same as Github instance hostname.

api-prefix: Github Enterprise much of the time uses "/api/v3/" as a
entry point to the API. Regular Github access does not need to
have a prefix specified. Consult your Github administrator for
the correct prefix to use.

use-ssh: Set to true in order to set the upstream remote reference
to use SSH instead of https.

## EXAMPLE

Create settings to prevent answering questions:

$ git config --global git-extras.github.com.user bigdog
$ git config --global git-extras.github.com.token d149feb47....
$ git config --global git-extras.github.com.add-api true
$ git config --global git-extras.github.com.use-ssl true

Fork expect.js:

$ git fork https://github.com/LearnBoost/expect.js
Expand Down Expand Up @@ -51,6 +92,8 @@ git-fork(1) -- Fork a repo on github

Written by Andrew Griffiths &lt;<[email protected]>&gt;

Github Enterprise support and settings by Gerard Hickey &lt;<[email protected]>&gt;

## REPORTING BUGS

&lt;<https://github.com/tj/git-extras/issues>&gt;
Expand Down