Comment obtenir un seul fichier d'une autre branche

1267

J'utilise git et travaille sur la branche master. Cette branche a un fichier appelé app.js.

J'ai une experimentbranche dans laquelle j'ai fait un tas de changements et des tonnes de commits. Maintenant , je veux apporter toutes les modifications effectuées qu'à app.jspartir experimentde la masterbranche.

Comment je fais ça?

Encore une fois, je ne veux pas de fusion. Je veux juste apporter tous les changements app.jsde experimentbranche en masterbranche.

Nick Vanderbilt
la source
1
Excepté la réponse et d'autres à ce jour, comment copier le contenu du fichier, c'est ce que je voulais moi-même quand j'ai trouvé celui-ci. Cependant, s'il est lu exactement, Nick voulait apporter des modifications, pas le texte intégral, et le fichier masterpeut différer experiment, par exemple peut contenir des modifications fusionnées d'autres branches qui seraient perdues dans le fichier est simplement copié. PS d'autre part, il ne veut pas fusionner, mais pour autant que je sache, le git mergeterme est pour branche uniquement, pas pour fichier spécifique, donc pas de contradiction ici.
Alexei Martianov

Réponses:

1605
git checkout master               # first get back to master
git checkout experiment -- app.js # then copy the version of app.js 
                                  # from branch "experiment"

Voir aussi git comment annuler les modifications d'un fichier?


Mise à jour d'août 2019, Git 2.23

Avec les nouvelles commandes git switchet git restore, ce serait:

git switch master
git restore -s experiment -- app.js

Par défaut, seule l'arborescence de travail est restaurée.
Si vous souhaitez également mettre à jour l'index (c'est-à-dire restaurer le contenu du fichier et l' ajouter à l'index en une seule commande):

git restore -s experiment --staged --worktree -- app.js
# shorter:
git restore -s experiment -WS -- app.js

Comme Jakub Narębski le mentionne dans les commentaires:

git show experiment:path/to/app.js > path/to/app.js

fonctionne aussi, sauf que, comme détaillé dans la question SO " Comment récupérer un seul fichier d'une révision spécifique dans Git? ", vous devez utiliser le chemin complet depuis le répertoire racine du référentiel.
D'où le chemin / to / app.js utilisé par Jakub dans son exemple.

Comme Frosty le mentionne dans le commentaire:

vous n'aurez que l'état le plus récent de app.js

Mais, pour git checkoutou git show, vous pouvez en fait référencer n'importe quelle révision que vous voulez, comme illustré dans la question SO " git checkout revision of a file in git gui ":

$ git show $REVISION:$FILENAME
$ git checkout $REVISION -- $FILENAME

serait le même si $ FILENAME est un chemin complet d'un fichier versionné.

$REVISIONpeut être comme indiqué dans git rev-parse:

experiment@{yesterday}:app.js # app.js as it was yesterday 
experiment^:app.js            # app.js on the first commit parent
experiment@{2}:app.js         # app.js two commits ago

etc.

schmijos ajoute dans les commentaires :

vous pouvez également le faire à partir d'une cachette:

git checkout stash -- app.js

Ceci est très utile si vous travaillez sur deux branches et que vous ne souhaitez pas vous engager.

VonC
la source
13
Une remarque: vous n'obtiendrez que l'état le plus récent de app.js, vous ne récupérerez aucun historique de la branche expérimentale.
Frosty
2
@ThomasReggi, vous devriez pouvoir importer (extraire) un fichier de n'importe quelle branche vers n'importe quelle branche actuelle. Si vous ne le pouvez pas, cela peut être une bonne question à poser ici, avec des détails spécifiques comme le message d'erreur exact et la version de Git et du système d'exploitation utilisés.
VonC
2
Dans un sous-répertoire, vous pouvez également utiliser experiment:./app.js. (Vous n'avez pas besoin de spécifier le chemin complet.) J'ai appris cela grâce au message d'erreur très utile que git m'a donné: "Vouliez-vous dire 'mybranch: full / path / to / my / file.xsl' aka 'mybranch: ./file.xsl '? " Oui je l'ai fait! Je ne pense pas avoir jamais été aussi ravi par un message d'erreur fatal.
Evan Lenz
1
@TomaszGandor Oui, je mentionne cela dans stackoverflow.com/a/21066489/6309 , où git show ne modifierait pas l'index, mais git checkout modifie l'index.
VonC
1
@FriedBrice Voir ma réponse: ces jours-ci, ce seraitgit restore -s new-feature path/to/app.js
VonC
360

Tout est beaucoup plus simple, utilisez git checkout pour cela.

Supposons que la you're on masterbranche, pour que la app.js from new-featurebranche fasse:

git checkout new-feature path/to/app.js

// note that there is no leading slash in the path!

Cela vous apportera le contenu du fichier souhaité. Vous pouvez, comme toujours, utiliser une partie de sha1 au lieu du nom de la nouvelle branche pour obtenir le fichier tel qu'il était dans ce commit particulier.

Remarque : new-featuredoit être une branche locale , pas distante.

Dmitry Avtonomov
la source
78
Je trouve utile de toujours spécifier l'origine git checkout origin/source_branch path/to/filecar si vous avez négligé de mettre à jour la branche source de votre dépôt local, vous pourriez obtenir une ancienne version du fichier ... Demandez-moi comment je sais. ;)
talyrique
3
@Mymozaaa, la question ne mentionnait pas les télécommandes, d'où l'hypothèse qu'il s'agit d'un dépôt purement local
Dmitry Avtonomov
1
Cette commande apportera-t-elle l'historique du fichier, ou tout simplement la dernière version du fichier?
user1366265
1
@ user1366265 cette commande mettra le fichier tel qu'il était dans le commit particulier que vous spécifiez ou le chef de la branche que vous spécifiez. Il n'y a rien de tel que "l'historique d'un fichier", toutes les informations d'historique sont uniquement stockées dans des branches.
Dmitry Avtonomov
3
Cela semble mettre automatiquement en scène le fichier extrait. Est-il possible de faire de même sans mise en scène?
bluenote10
44
git checkout branch_name file_name

Exemple:

git checkout master App.java

Cela ne fonctionnera pas si le nom de votre branche contient un point.

git checkout "fix.june" alive.html
error: pathspec 'fix.june' did not match any file(s) known to git.
Sarath
la source
@PhilipRego Cette réponse est correcte. Je suppose qu'il y a des majuscules ou des signes de ponctuation différents dans votre branche, ou vous n'avez qu'une branche distante et non locale. Voir le document git checkout: git-scm.com/docs/git-checkout#Documentation/…
Bret
@Bret J'ai trouvé que cela ne fonctionne pas lorsque le nom de la branche a un point. J'ai suggéré une modification
Philip Rego
C'est la meilleure réponse. Je souhaite que cette réponse soit la mieux notée. Le plus haut actuel est très déroutant et pas simple
Russell Lego
41

Complément aux réponses de VonC et de chhh.

git show experiment:path/to/relative/app.js > app.js
# If your current working directory is relative than just use
git show experiment:app.js > app.js

ou

git checkout experiment -- app.js
AlexLordThorsen
la source
2
Cool! Je déteste spécifier les longs chemins. Le double tiret ( --) entre le nom de la branche et les chemins est-il facultatif? Est-ce uniquement pour empêcher que des chemins, qui commenceraient par un tiret, soient traités comme des options / commutateurs?
Tomasz Gandor
Honnêtement, je ne sais pas. Je n'ai même pas remarqué que j'avais oublié le double tiret jusqu'à ce que vous le signaliez.
AlexLordThorsen
6
@TomaszGandor Le --est facultatif, mais il est plus utile d'éviter les conflits avec les noms de branche. Par exemple, git checkout -- foosignifie «extraire le fichier foo de HEAD» (c'est-à-dire écraser les modifications locales dans foo , c'est-à-dire un sous-ensemble de git reset --hard), mais git checkout foopourrait signifier cela ou «allons à la branche foo ».
Alois Mahdal
8

Ou si vous voulez tous les fichiers d'une autre branche:

git checkout <branch name> -- .
fou du roi
la source
24
Le queston initial contient "un seul fichier".
greatvovan
1
cela remplace les fichiers existants plutôt que de les fusionner
Amare
3
Cela .fait une énorme différence: au lieu de passer à une autre branche, il copie tous les fichiers à partir de là tout en vous laissant sur la branche actuelle. Vous obtenez le contenu d'une autre branche sans y entrer.
Xeverous
4

Examinez le fichier sur github et tirez-le de là

Il s'agit d'une approche pragmatique qui ne répond pas directement au PO, mais certains ont trouvé utile:

Si la branche en question se trouve sur GitHub, vous pouvez accéder à la branche et au fichier souhaités à l'aide de l'un des nombreux outils proposés par GitHub, puis cliquer sur 'Raw' pour afficher le texte brut et (facultativement) copier et coller le texte comme voulu.

J'aime cette approche car elle vous permet de regarder le fichier distant dans son intégralité avant de le tirer sur votre machine locale.

intrépide_fool
la source
2
Cependant, copier et coller le fichier brut est susceptible de provoquer des changements de caractères indésirables dans votre diff git. Il est plus sûr d'enregistrer le fichier directement dans votre projet pour éviter toute modification.
Philip Rego
0

Si vous voulez le fichier d'un commit particulier (n'importe quelle branche), dites 06f8251f

git checkout 06f8251f path_to_file

par exemple, dans les fenêtres:

git checkout 06f8251f C: \ A \ B \ C \ D \ file.h

arupjbasu
la source
1
Merci d'avoir pris le temps de répondre! Mais cela ne répond pas à la question, et une bonne réponse très détaillée a déjà été postée il y a 9 ans. Il n'est pas nécessaire de se poser la question.
Nathan
Il s'agit d'un scénario pratique valable. La réponse traite correctement de la branche, mais qu'en est-il de regarder un commit particulier de la branche.
arupjbasu
0

Une autre façon est de créer un patch avec les différences et de l'appliquer dans la branche master Par exemple. Disons que le dernier commit avant de commencer à travailler sur app.js est 00000aaaaa et que le commit contenant la version souhaitée est 00000bbbbb

Vous exécutez ceci sur la branche d'expérience:

git diff 00000aaaaa 00000bbbbb app.js > ~/app_changes.git

Cela va créer un fichier avec toutes les différences entre ces deux validations pour app.js que vous pouvez appliquer où vous le souhaitez. Vous pouvez conserver ce fichier n'importe où en dehors du projet

Ensuite, en master, vous exécutez simplement:

git apply ~/app_changes.git

vous allez maintenant voir les changements dans les projets comme si vous les aviez faits manuellement.

Santi
la source
-3
git checkout master               -go to the master branch first
git checkout <your-branch> -- <your-file> --copy your file data from your branch.

git show <your-branch>:path/to/<your-file> 

J'espère que cela vous aidera. Veuillez me le faire savoir si vous avez des questions.

Rohit Saini
la source