2012-05-11 19 views
11

Io chiaramente non capisco affatto git. Questo è quello che sto ottenendo:git staging e commit tra più rami

git branch (outputs that I'm on master) 
git checkout -b foo 
echo "next line" >> file (file is an existing file) 
git add file (stages) 
git checkout master 
git status (shows that file has "next line" and is staged!!) 
git commit (commits the changes that were staged on branch foo!!) 
git checkout foo 

Ecco il kicker. pippo ora non mostra alcuna modifica apportata al file nella directory di lavoro O messo in scena.

Quindi sembra che tutte le modifiche apportate, inclusi la modifica di file e la gestione temporanea, avvengano su TUTTI i rami. e quando si COMMIT su un ramo specifico, tali modifiche vengono scartate su tutti gli altri rami eccetto quello su cui si è effettuato il commit.

È questo che sta succedendo? Qualcuno può aver senso per me? Sembra un comportamento completamente fasullo e chiaramente non ho un'idea di design che renda questa cosa sensata.

Modifica per esempio esplicito:

$ mkdir element 
$ cd element 
$ git init 
Initialized empty Git repository in /home/dan/element/.git/ 
$ echo "one" >> one 
$ git add one 
$ git commit -m msg 
[master (root-commit) 36dc8b0] msg 
1 files changed, 1 insertions(+), 0 deletions(-) 
create mode 100644 one 
$ git checkout -b fire 
Switched to a new branch 'fire' 
$ echo "next line" >> one 
$ git checkout master 
M  one 
Switched to branch 'master' 
$ cat one 
one 
next line 
$ 

che contraddice palesemente questo dal git pro libro:

This is an important point to remember: Git resets your working directory to look like the snapshot of the commit that the branch you check out points to. It adds, removes, and modifies files automatically to make sure your working copy is what the branch looked like on your last commit to it.

+2

La mia risposta aiuta a chiarire le cose? Penso che sia antecedente alla tua modifica, ma non ne sono completamente sicuro. – larsks

risposta

9

Non importa quale ramo si è in quando si aggiunge un file, solo quando si commit esso. Quindi se lo fai:

git add file 
git checkout master 
git commit 

Hai impegnato il file nel ramo principale.

Ecco un esempio completo, con output. Si comincia con un nuovo repository:

$ git init 
Initialized empty Git repository in /home/lars/tmp/so/repo/.git/ 

A questo punto, siamo sul ramo master e non abbiamo ancora aggiunto alcun file. Aggiungiamo un file:

$ date > file1 
$ cat file1 
Fri May 11 13:05:59 EDT 2012 
$ git add file1 
$ git commit -m 'added a file' 
[master (root-commit) b0764b9] added a file 
1 files changed, 1 insertions(+), 0 deletions(-) 
create mode 100644 file1 

Grande, ora abbiamo un ramo (master) con un commit. Creiamo la nuova filiale:

$ git checkout -b foo 
Switched to a new branch 'foo' 
$ git branch 
* foo 
    master 
$ ls 
file1 

Ora aggiungeremo una linea per file1.

$ date >> file1 
$ git status 
# On branch foo 
# Changes not staged for commit: 
# (use "git add <file>..." to update what will be committed) 
# (use "git checkout -- <file>..." to discard changes in working directory) 
# 
#  modified: file1 
# 
no changes added to commit (use "git add" and/or "git commit -a") 

Questo mostra che il file è stato modificato, ma non ancora messo in scena. Andiamo in scena il file e la commetterlo:

$ git add file1 
$ git commit -m 'made a change' 
[foo 761bed9] made a change 
1 files changed, 1 insertions(+), 0 deletions(-) 

e rieseguire git status:

$ git status 
# On branch foo 
nothing to commit (working directory clean) 

A questo punto, il file è simile al seguente:

Fri May 11 13:05:59 EDT 2012 
Fri May 11 13:07:36 EDT 2012 

Se tornare a il ramo master, vedremo la versione precedente del file senza la seconda riga:

$ git checkout master 
Switched to branch 'master' 
$ cat file1 
Fri May 11 13:05:59 EDT 2012 

Le modifiche a un file vengono isolate nel ramo su cui sono state eseguite le commit.

Nel tuo esempio aggiornato, questo ...

$ git checkout master 

... non genera un errore perché, a questo punto, la versione di 'uno' sia in master e fire è identico. Le modifiche nella directory di lavoro si applicano ugualmente bene a entrambe le versioni.

+1

Sì - se lavori su un ramo atomicamente rispetto a commit tutto funziona come in questo esempio e ha senso per me. Se modifichi e possiedi stage senza commit e poi cambi rami, allora entri in questo strano stato loopy che è accaduto nel mio primo post. La morale semplicemente non cambia mai rami senza commettere? Tuttavia: se faccio questo nella direzione opposta e lavoro su master e passa al fuoco di ramo, mi dà un errore: 'error: Hai modifiche locali a 'uno'; impossibile cambiare ramo. Non so perché non ho ricevuto questo errore mentre lavoravo nell'altra direzione. – djechlin

+1

Il file è stato effettivamente rintracciato prima di eseguire 'git add'? È possibile riorganizzare la domanda utilizzando un repository di esempio che mostra i comandi e l'output effettivi? In generale, è comune sia commit che [stash] (http://git-scm.com/book/en/Git-Tools-Stashing) le modifiche prima di cambiare ramo. – larsks

+1

Domanda modificata per mostrare il dialogo completo invece dei soli comandi. Guarderò nella scorta - sembra che non capisco come i rami "superficiali" siano davvero in grado di dare. Non capisco perché git mi faccia fare un checkout sporco però. – djechlin

2

L'indice dell'area di gestione temporanea è comune a tutte le filiali, il che spiega la tua osservazione