dosyanın bir sürümünü gizli tutmak için github stratejisi


11

Öğrenciler için kodlama problemleri yazan bir öğretim görevlisiyim. Yapmak istediğim şey, öğrencilere tamamlayacakları fonksiyonlar için yer tutucularla birlikte kaynak levhası kodunu vermektir. Bunu klonlamak için öğrencilere özel bir github deposuna erişim vereceğim.

Ancak, ben de örnek çözümler ile komple, kod temeli bir sürümünü istiyorum. Açıkçası öğrencilerin çözüme erişmelerini istemiyorum (ödev bitene kadar).

Şubeleri düşündüm, ama AFAIK, bir şubeyi özel tutamıyorum.

Belki projeyi başka bir özel repoya yerleştirebilirim, ancak projeleri snyc'de (çözümü içeren dosya dışında) nasıl tutabileceğimden emin değilim.

Bu durum için bir iş akışı var mı?


1
Ben öyle düşünmüyorum. Ama ne soğuyorsun: uygulanacak yöntemler için delcare arayüzleri. Öğrenci-kamu Repo'nuzda, boş yöntem gövdeleri ile bu arabirimleri uygulayan sınıflar oluşturun. Çözümleri ayrı bir özel depoda saklayın. Bu, senkronizasyon sorununuzu tamamen çözmez, ancak görevlerin kapsamına indirir.
marstato

şubelere erişimi kontrol etmek için github API'sini kullanmaya başladınız mı?

Yanıtlar:


8

Ne yapılabilir?

  • 2 depo oluşturun: öğrenci ve öğretmen.
  • Onları makinenize kopyalayın (Github istemcisi ile yapılabilir)
  • Sen sadece öğretmen çalışmak , hiçbir zaman öğrenci dokunun.

Dizin yapınız 2 klonlanmış git repo's:

  • / student (.git klasörü ile)
  • / teacher (bir .git klasörü ile)

Dilinize ilişkin yorumlarda "özel" kodun etrafına işaretçiler koydunuz, örneğin aşağıdaki javascript. İşaretçiler özel kodun başladığı ve bittiği yeri belirtir.

function sum(a, b) {
  // -----------------------START
  return a + b; // so this is what you expect from the student
  // -----------------------END
}

console.log(sum(1,1)); // I expect 2 as a result of your homework

Ardından yerel makinenizde basit bir komut dosyası oluşturun:

files.forEach((fileContent, fileName) => {
  let newFileContent = '';
  let public = true;
  fileContent.forEach((line) => {
    switch(line) {
      case '// -----------------------START':
        public = false;
        break;
      case '// -----------------------END':
        public = true;
        break;
      default:
        if(public) {
          newFileContent = newFileContent + line + "\n";
        }
    }
  });
  writeFile('../student/' + fileName, newFileContent);
});

Tüm dosyalarınızı alır ve içeriği kodun özel işaretli kısımları olmadan / öğrenciye (üzerine yazma) kopyalar. İsterseniz oraya boş çizgiler ekleyebilirsiniz, ancak bu ne tür bir çözüm beklediğinize dair bir ipucu verebilir.

Bu test edilmemiş örnek kod, bu yüzden muhtemelen bazı hata ayıklama yapmak zorunda.

Şimdi yapmanız gereken tek şey, çıktıdan memnun olduğunuzda öğrenci deposunu teslim etmek ve zorlamaktır. Bu, GitHub istemcisini kullanırken tek bir tıklamayla yapılabilir (böylece hızlı bir görsel inceleme yapabilirsiniz) veya komut satırında manuel olarak yapabilirsiniz.

Öğrenci repo sadece bir çıkış deposudur, bu yüzden her zaman güncel kalacaktır, öğrencilere taahhütlere bakarak nelerin değiştiği açıktır (çünkü sadece değişiklikleri gösterirler) ve kullanımı kolaydır.

Bir adım daha, komut dosyanızı otomatik olarak çalıştıran bir git kesinleştirme kancası oluşturmak olacaktır.

Düzenle: Yayınınızda bir düzenleme yaptığınızı görün:

Açıkçası öğrencilerin çözüme erişmelerini istemiyorum (ödev bitene kadar).

Açık ama şüpheleniyorum: Sadece bitmiş egzersizin etrafındaki etiketleri kaldırmak, cevabı alıştırmalarda normal güncellemeler için yaptığınız şekilde yayınlayacaktır.


bazı git voodoo ile bunu yapabileceğini umuyordum, ancak çözüm çok pratik.
Ken

@Ken de bunu düşünüyordu ama yanlış iş için biraz yanlış bir araç. Git birleştirir, günceller vb. Ancak genel olarak kod seçmek bir fikir değildir. Kod tabanınızı birden çok makinede tutarlı tutmanız iyi olur. Bu yüzden başka bir çözüm geliştirdim. Bu yaklaşımla ilgili sevdiğim şey, riski ve emeği minimuma indirmesi ve buna ayak uydurması kolay. Ve sonunda, öğrencilerinize iyi bir örnek vermek için taahhüt mesajınızı yine de öğrenci repoya yazmalısınız;)
Luc Franken

Git'in değişiklikleri takip etmesine yardımcı olmak için öğretmen deponuzda bir öğrenci şubesi oluşturabilirsiniz, birleştirirken (veya işaretçiler arasındaki herhangi bir şeyi kaldırarak el ile birleştirerek) komut dosyasını çalıştırın. Ardından öğrenci şubesini yerel olarak senkronize edin ve öğretmen kaynağından ziyade öğrenci deposuna aktarın. Bu şekilde git, değişiklikleri izlemek ve geçmişin bir repodan diğerine doğru bir şekilde iletilmesini sağlamak için daha iyi durumda olur. Her iki dünyanın en iyisi. Seni bu aklı denemedim ama neden işe yaramadığını anlamıyorum.
Newtopian

1
Başlangıç ​​sonu etiketlerini kaldırma fikri dışında bunu beğendim. "Çözüm" kelimesini ekleyerek onları manipüle etmek daha iyidir.
candied_orange

@CandiedOrange da hoş bir şey, buna katılıyorum. Çözüm aynı zamanda bazı farklı biçimlendirmelere izin verir ve unutulan etiketler ile çözümün yayınlanması gereken gerçek karar arasında açıkça ayrım yapar. @ newtopian: Bunu düşünüyordum ama yeterince avantaj görmedim. Ayrıca öğrenci çıktısını tamamen farklı bir kod olarak görmeye karar verdim. Bu gerçek kaynak değil, bu yüzden yapmamaya karar verdim. Öğretmen deposundaki şubelerle ne yapacağım örneğin: Gelecek dönem için görevler üzerinde çalışmak. Hazır olduğunuzda, onları master yapmak için birleştirir ve betiği çalıştırırsınız.
Luc Franken

6

Yapabilirdin

  • Ortak etiket kodunu işlerseniz herkese açık bir GitHub deposu oluşturun
  • Bu havuzu özel bir GitHub havuzu olarak çatalla
  • Çatallı depodaki ödevleri çözme
  • Atama tamamlandığında her bir çözümü halka açık depoda birleştirin

Ben bu iş akışını nasıl uygular:

  • assignmentsGitHub'da barındırılan genel bir havuz oluşturun . Ödevler için kaynak plakasını ekleyin. Örneğin, her atama için atamanın ortak kodunu içeren yeni bir alt dizin tanıtırsınız.
  • GitHub'da yeni bir özel havuz oluşturun assignments-solved. Repo'yu assignmentsmakinenizde klonlayın ve repoya itin assignments-solved (esas olarak kendi havuzunuzu özel bir kopya olarak çatallayın): git clone https://github.com/[user]/assignments assignments-solved cd assignments-solved git remote set-url origin https://github.com/[user]/assignments-solved git push origin master git push --all
  • assignments-solvedRepoyu repoya uzak olarak ekleyin assignments: cd assignments # change to the assignments repo on your machine git remote add solutions https://github.com/[user]/assignments-solved
  • Her atamayı assignments-solveddepoya uygulayın. Her bir taahhüdün yalnızca bir ödevdeki değişiklikleri içerdiğinden emin olun.
  • Orijinal atamaların değiştirilmemesi solvediçin assignmentsrepoda bir şube oluşturmak isteyebilirsiniz : cd assignments # change to the assignments repo on your machine git branch -b solutions git push -u origin
  • İçine bir çözüm yayınlamak istediğinizde assignments, solveduzaktan kumandayı ve cherry-pickçözümleri içeren taahhütleri alın. cd assignments # change to the assignments repo on your machine git checkout solved git fetch solutions git cherry-pick [commithash] Nerede [commithash]içeren çözeltinin taahhüt.

Ayrıca, her atamayı repo'nun ayrı bir dalına uygulayıp assignments-solvedsonra repoda bir çekme isteği oluşturarak da iş akışını uygulayabilirsiniz assignments. Ancak assignments-solvedrepo gerçek bir çatal olmadığından bunun GitHub'da çalışıp çalışmayacağından emin değilim .


Bir programlama testini gönderilen cevaplardan ayırmak için benzer bir yöntemi başarıyla kullandım. Benim durumumda, sunulan çözümler özel bir klonun bireysel dallarına eklenir ve asla halka repo ile birleştirilmez. Ek olarak, her bir adayın zaman içinde geliştikçe testin hangi versiyonunu çözdüğünü görmeme izin veriyor.
aks

0

Size sadece .gitignoredeponuzdaki dosyaları göndermeyi ve şifrelemeyi amaçlayan bir yardımcı program önerebilirim . İş akışının kullanımı biraz zordur, ancak dosyalarınızın şifrelenmiş meslektaşlarını, her zamanki gibi git ile izlemenizi sağlayan diğer gizli olmayan dosyalarla birlikte çalışma kopyasında kullanılabilir hale getirir.

#!/bin/bash

set -o errexit
set -o pipefail
set -o nounset

version=1
OPTIND=1
verbose=0
mode="add"
recurse=()
files=()

while getopts ":vaslr:" opt
do
    case "$opt" in
        \?) echo "error: invalid option: -$OPTARG" >&2 ; exit 1
            ;;
        :)  echo "error: option -$OPTARG requires an argument" >&2 ; exit 1
            ;;
        v)  let "verbose++" ; echo "verbosity increased"
            ;;
        a)  mode="add"
            ;;
        s)  mode="save"
            ;;
        l)  mode="load"
            ;;
        r)  recurse+=("$OPTARG")
            ;;
    esac
done
shift $((OPTIND-1))
if [[ "${#recurse[@]}" != 0 ]] 
then
    for pattern in "${recurse[@]}" 
    do
        while IFS= read -d $'\0' -r file
        do
            files+=("$file")
        done < <(find . -name "$pattern" -type f -print0)
    done
else
    files=("$@")
fi

[[ "${#files[@]}" != 0 ]] || { echo "list of files to process is empty" >&2 ; exit 1 ; }

if [[ $mode == "add" ]]
then
    for file in "${files[@]}"
    do
        [[ -e $file ]] && cp "$file" "${file}.bak" || touch "$file"
        sshare_file="${file}.sshare"
        [[ -e $sshare_file ]] || { echo "$version" > "$sshare_file" ; git add --intent-to-add "$sshare_file" ; echo "$file" >> .gitignore ; echo "${file}.bak" >> .gitignore ; git add .gitignore ; }
    done
    exit 0
fi
tmp_dir=`mktemp --tmpdir -d sshare.XXXX`
read -r -s -p "enter password to $mode tracked files:" sshare_password && echo ;
for file in "${files[@]}"
do
    [[ ! -e $file ]] && touch "$file" || cp "$file" "${file}.bak"
    sshare_file="${file}.sshare"
    [[ -r $sshare_file ]] || { echo "warning: can't read file '$sshare_file' (file '$file' skipped)" >&2 ; continue ; }
    file_version=$(head -1 "$sshare_file")
    [[ "$file_version" == $version ]] || { echo "warning: version '$file_version' of '$sshare_file' file differs from version '$version' of script (file '$file' skipped)" >&2 ; continue ; }
    tmp_file="$tmp_dir/$file"
    mkdir -p "$(dirname "$tmp_file")"
    > "$tmp_file"
    line_number=0
    while IFS= read -r line
    do
        let "line_number++" || :
        [[ -n $line ]] || { echo "warning: empty line encountered at #$line_number in file '$sshare_file' (ignored)" >&2 ; continue ; }
        echo "$line" | openssl enc -d -A -base64 -aes256 -k "$sshare_password" | gunzip --to-stdout --force | patch "$tmp_file" --normal --quiet
    done < <(tail --lines=+2 "$sshare_file")
    if [[ $mode == "load" ]]
    then
        cp -f "$tmp_file" . || { echo "warning: can't write to file '$file' (file '$file' skipped)" >&2 ; continue ; }
    elif [[ $mode == "save" ]]
    then
        chunk=$(diff "$tmp_file" "$file" || :)
        [[ -n $chunk ]] || { echo "nothing to comit since last edit for file '$file'" ; continue ; }
        [[ -w $sshare_file ]] || { echo "warning: can't update sshare database '$sshare_file' (file '$file' skipped)" ; continue ; }
        echo "$chunk" | gzip --stdout | openssl enc -e -A -base64 -aes256 -k "$sshare_password" >> "$sshare_file"
        echo >> "$sshare_file"
        echo "changes encrypted for file '$file'"
    fi
done

Dosya adı a.txttürüyle gizli dosya oluşturmak için sshare -a a.txt. Yardımcı program dosya a.txtve dosya eklendi .gitignore. Daha sonra dosya adına uzantı a.txt.sshareekleyerek şifreli "veritabanı" karşılığı oluşturur .sshare.

Sonra a.txtbazı metinlerle doldurabilirsiniz . Önce, devlet hakkı kaydetmek için git committip sshare -s a.txt, şifre daha sonra yarar istemi dosyanın yeni halini şifrelemek için a.txt. Sonra bu parolayı kullanarak utilty dosya a.txtsonuna önceki ve geçerli dosya durumu arasında şifreli fark ekler a.txt.sshare.

Şifrelenmiş dosyalar ile depo getirildikten / çekildikten sonra ("yükle") anahtarını ssharekullanarak her dosya için yardımcı programı çalıştırmalısınız -l. Bu durumda, yardımcı program, *.ssharedosyaların çalışma kopyasında git tarafından izlenmeyen metin dosyalarının şifresini çözer .

Her gizli dosya için farklı şifreler kullanabilirsiniz.

Yarar parçaya git (verimli değiştirir verir fark ait .ssharedosyaların sadece bir satır olduğunu).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.