3

I have a GitHub repository for my dotfiles here.

It contains an installdotfiles.sh script to install the dotfiles from GitHub. I would like to have another git repository on GitLab for backup (and the really cool custom syntax-highlighting :P), mirroring this repository, except running the shell command on the repository:

grep -rl raw.githubusercontent . | 
      xargs sed -i ''
     's/raw.githubusercontent/gitlab/g'; grep -rl 'dotfiles/master' . |
      xargs sed -i '' 's/dotfiles\/master/dotfiles\/raw\/master/g'

which replaces the links to Github with the corresponding links to GitLab.

Basically, if I push to my GitHub dotfiles repository, I would my GitLab repository to automatically update, except run the script on the repository first, so I have my GitLab repository contains the GitLab links.

How would I implement such a hook?

I have heard that this can be implemented using Git Hooks, however I am unfamiliar with them, and reading about them, I don't exactly understand how such a thing would be done.

P.S it would be nice if it works both ways - so when I push to GitLab, GitHub will run a different script that replaces GitLab links with GitHub links, so that whenever I push to one, both update accordingly.

CodeWizard
  • 128,036
  • 21
  • 144
  • 167
thepiercingarrow
  • 211
  • 4
  • 17

2 Answers2

1

The simplest approach is making your script installdotfiles.sh use an variable, that you set (before calling your script) depending on the repo you want to fetch your files.

For instance:

origin=github curl https://raw.githubusercontent.com/thepiercingarrow2/dotfiles/master/installdotfiles.sh | sh
# or
origin=gitlab curl https://gitlab.com/thepiercingarrow2/dotfiles/raw/master/.bash_profile | sh

That means your script include a simple test:

remote="raw.githubusercontent.com/thepiercingarrow2/dotfiles"
if [[ "${origin}" == "gitlab" ]]; then
   remote="gitlab.com/thepiercingarrow2/dotfiles/raw"
fi

#bash_profile
curl -# https://${remote}/master/.bash_profile > ~/.bash_profile

In other words, you really do not need a git hook. Of any kind.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • That works +1. However, if I *were* to use hooks, how would I do so? Or is it not possible? – thepiercingarrow Mar 23 '16 at 23:25
  • @MarkWright no it is not for your case. On the client side, you would need a complex hook in order to change the content you want to push to the remote side (GitHub or GitLab). On the server side, you cannot add hooks, only webhook (https://developer.github.com/webhooks/). Again, the complexity is not worth it. The ill-advised "answer" below cannot be applied to a GitHub or GitLab remote repo. – VonC Mar 24 '16 at 06:54
  • Okay, thanks. How would I use a webhook? I was looking at that, but I couldn't figure out what to put for my URL and my "secret" (again, super inexperienced with git). – thepiercingarrow Mar 24 '16 at 13:52
  • @MarkWright That is a different question, which does not apply to your original topic though. – VonC Mar 24 '16 at 13:54
  • Okay, thanks. So, if I use this method, could a script sort of 'ping' GitHub, if it responds, then set remote to Github, and if it is down, use GitLab as a backup? – thepiercingarrow Mar 24 '16 at 13:58
  • @MarkWright sure, a simple curl can be enough (http://stackoverflow.com/a/2924444/6309) – VonC Mar 24 '16 at 14:01
0

How would I implement such a hook?

You can choose any hook you like and check the links in the files.

For example you can use something like this and add your line of script after the if condition.

pre-receive hook

#!/bin/sh

# Check to see if this is the first commit in the repository or not
if git rev-parse --verify HEAD >/dev/null 2>&1
then
    # We compare our changes against the previous commit
    against=HEAD^
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Redirect output to screen.
exec 1>&2

# Get the list of files which were commits
# assuming the other files are already contains the right values and does not need to be updated
files = $(git diff-tree -r --name-only $against )

# ... do whatever you want to do with the files

P.S it would be nice if it works both ways - so when I push to GitLab, GitHub will run a different script that replaces GitLab links with GitHub links, so that whenever I push to one, both update accordingly.

Set 2 hooks, i on each repository with the right links with the right value on each repo.


Another approach not using hooks:

If you can have local code on your client side you can use this feature in git:

It turns out that you can write your own filters for doing substitutions in files on commit/checkout. These are called clean and smudge filters.

enter image description here

Read all about it here:
https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#Keyword-Expansion

CodeWizard
  • 128,036
  • 21
  • 144
  • 167
  • +1 Thanks for the response! This makes sense, but I am inexperienced with git, and unsure how I would do this. Would this do the substitution whenever it receives an update on the repository, or locally when committing, or am I totally missing the point? Thanks. – thepiercingarrow Mar 23 '16 at 23:28